Line data Source code
1 : //# MSTransformRegridder.cc: This file contains the implementation of the MSTransformRegridder class.
2 : //#
3 : //# CASA - Common Astronomy Software Applications (http://casa.nrao.edu/)
4 : //# Copyright (C) Associated Universities, Inc. Washington DC, USA 2011, All rights reserved.
5 : //# Copyright (C) European Southern Observatory, 2011, All rights reserved.
6 : //#
7 : //# This library is free software; you can redistribute it and/or
8 : //# modify it under the terms of the GNU Lesser General Public
9 : //# License as published by the Free software Foundation; either
10 : //# version 2.1 of the License, or (at your option) any later version.
11 : //#
12 : //# This library is distributed in the hope that it will be useful,
13 : //# but WITHOUT ANY WARRANTY, without even the implied warranty of
14 : //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : //# Lesser General Public License for more details.
16 : //#
17 : //# You should have received a copy of the GNU Lesser General Public
18 : //# License along with this library; if not, write to the Free Software
19 : //# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 : //# MA 02111-1307 USA
21 : //# $Id: $
22 :
23 : #include <mstransform/MSTransform/MSTransformRegridder.h>
24 :
25 : using namespace casacore;
26 : namespace casa { //# NAMESPACE CASA - BEGIN
27 :
28 : /////////////////////////////////////////////
29 : /// MSTransformRegridder implementation ///
30 : /////////////////////////////////////////////
31 :
32 : // -----------------------------------------------------------------------
33 : //
34 : // -----------------------------------------------------------------------
35 0 : MSTransformRegridder::MSTransformRegridder()
36 : {
37 0 : return;
38 : }
39 :
40 : // -----------------------------------------------------------------------
41 : //
42 : // -----------------------------------------------------------------------
43 0 : MSTransformRegridder::~MSTransformRegridder()
44 : {
45 0 : return;
46 0 : }
47 :
48 :
49 : // -----------------------------------------------------------------------
50 : // Make one spectral window from all SPWs given by the SPW Ids vector
51 : // -----------------------------------------------------------------------
52 90 : Bool MSTransformRegridder::combineSpws( LogIO& os,
53 : String msName,
54 : const Vector<Int>& spwids,
55 : Vector<Double>& newCHAN_FREQ,
56 : Vector<Double>& newCHAN_WIDTH,
57 : vector<vector<Int> >& averageWhichChan,
58 : vector<vector<Int> >& averageWhichSPW,
59 : vector<vector<Double> >& averageChanFrac,
60 : Bool verbose)
61 : {
62 90 : MeasurementSet ms_p(msName, Table::Old);
63 90 : Bool result = false;
64 90 : result = combineSpwsCore(os,ms_p,spwids,newCHAN_FREQ,newCHAN_WIDTH,
65 : averageWhichChan, averageWhichSPW, averageChanFrac, verbose);
66 180 : return result;
67 : }
68 :
69 : // -----------------------------------------------------------------------
70 : // Make one spectral window from all SPWs given by the SPW Ids vector
71 : // -----------------------------------------------------------------------
72 233 : Bool MSTransformRegridder::combineSpwsCore( LogIO& os,
73 : MeasurementSet& ms_p,
74 : const Vector<Int>& spwids,
75 : Vector<Double>& newCHAN_FREQ,
76 : Vector<Double>& newCHAN_WIDTH,
77 : vector<vector<Int> >& averageWhichChan,
78 : vector<vector<Int> >& averageWhichSPW,
79 : vector<vector<Double> >& averageChanFrac,
80 : Bool verbose)
81 : {
82 : // Analyze SPW Ids
83 233 : if (spwids.nelements() == 0)
84 : {
85 0 : os << LogIO::WARN << LogOrigin("MSTransformRegridder", __FUNCTION__)
86 0 : << "No SPWs selected for combination ..." << LogIO::POST;
87 0 : return true;
88 : }
89 :
90 : // Find all existing spws,
91 466 : MSSpectralWindow spwtable = ms_p.spectralWindow();
92 233 : Int origNumSPWs = spwtable.nrow();
93 :
94 466 : vector<Int> spwsToCombine;
95 466 : Vector<Bool> includeIt(origNumSPWs, false);
96 :
97 : // jagonzal: This covers for the case when we want to combine all the input SPWs
98 233 : if (spwids(0) == -1)
99 : {
100 714 : for (Int i = 0; i < origNumSPWs; i++)
101 : {
102 624 : spwsToCombine.push_back(i);
103 624 : includeIt(i) = true;
104 : }
105 : }
106 : // jagonzal: Nominal case when we want to combine a sub-set of the input SPWs
107 : else
108 : {
109 547 : for (uInt i = 0; i < spwids.nelements(); i++)
110 : {
111 404 : if (spwids(i) < origNumSPWs && spwids(i) >= 0)
112 : {
113 404 : spwsToCombine.push_back(spwids(i));
114 404 : includeIt(spwids(i)) = true;
115 : }
116 : else
117 : {
118 0 : os << LogIO::SEVERE << LogOrigin("MSTransformRegridder", __FUNCTION__)
119 : << "Invalid SPW ID selected for combination "
120 0 : << spwids(i) << "valid range is 0 - "
121 0 : << origNumSPWs - 1 << ")" << LogIO::POST;
122 0 : return false;
123 : }
124 : }
125 : }
126 :
127 : // jagonzal: Marginal case when there is no actual SPW combination
128 233 : if (spwsToCombine.size() <= 1)
129 : {
130 0 : if (verbose)
131 : {
132 0 : os << LogIO::NORMAL << LogOrigin("MSTransformRegridder", __FUNCTION__)
133 : << "Less than two SPWs selected. No combination necessary."
134 0 : << LogIO::POST;
135 : }
136 0 : return true;
137 : }
138 :
139 : // Sort the SPW Ids
140 233 : std::sort(spwsToCombine.begin(), spwsToCombine.end());
141 :
142 233 : uInt nSpwsToCombine = spwsToCombine.size();
143 :
144 : // Prepare access to the SPW table
145 466 : MSSpWindowColumns SPWColrs(spwtable);
146 466 : ScalarColumn<Int> numChanColr = SPWColrs.numChan();
147 466 : ArrayColumn<Double> chanFreqColr = SPWColrs.chanFreq();
148 466 : ArrayColumn<Double> chanWidthColr = SPWColrs.chanWidth();
149 466 : ScalarColumn<Int> measFreqRefColr = SPWColrs.measFreqRef();
150 466 : ArrayColumn<Double> effectiveBWColr = SPWColrs.effectiveBW();
151 466 : ScalarColumn<Double> refFrequencyColr = SPWColrs.refFrequency();
152 466 : ArrayColumn<Double> resolutionColr = SPWColrs.resolution();
153 466 : ScalarColumn<Double> totalBandwidthColr = SPWColrs.totalBandwidth();
154 :
155 : // Create a list of the SPW Ids sorted by first (lowest) channel frequency
156 466 : vector<Int> spwsSorted(nSpwsToCombine);
157 466 : Vector<Bool> isDescending(origNumSPWs, false);
158 233 : Bool negChanWidthWarned = false;
159 :
160 :
161 233 : Double* firstFreq = new Double[nSpwsToCombine];
162 233 : uInt count = 0;
163 1267 : for (uInt i = 0; (Int) i < origNumSPWs; i++)
164 : {
165 1034 : if (includeIt(i))
166 : {
167 1028 : Vector<Double> CHAN_FREQ(chanFreqColr(i));
168 :
169 : // If frequencies are ascending, take the first channel, otherwise the last
170 1028 : uInt nCh = CHAN_FREQ.nelements();
171 1028 : if (CHAN_FREQ(0) <= CHAN_FREQ(nCh - 1))
172 : {
173 1000 : firstFreq[count] = CHAN_FREQ(0);
174 : }
175 : else
176 : {
177 28 : firstFreq[count] = CHAN_FREQ(nCh - 1);
178 28 : isDescending(i) = true;
179 : }
180 1028 : count++;
181 : }
182 : }
183 :
184 466 : Sort sort;
185 233 : sort.sortKey(firstFreq, TpDouble); // define sort key
186 466 : Vector<uInt> inx(nSpwsToCombine);
187 233 : sort.sort(inx, nSpwsToCombine);
188 1261 : for (uInt i = 0; i < nSpwsToCombine; i++)
189 : {
190 1028 : spwsSorted[i] = spwsToCombine[inx(i)];
191 : }
192 233 : delete[] firstFreq;
193 :
194 :
195 233 : Int id0 = spwsSorted[0];
196 :
197 233 : uInt newNUM_CHAN = numChanColr(id0);
198 233 : newCHAN_FREQ.assign(chanFreqColr(id0));
199 233 : newCHAN_WIDTH.assign(chanWidthColr(id0));
200 233 : Bool newIsDescending = isDescending(id0);
201 : {
202 233 : Bool negativeWidths = false;
203 23068 : for (uInt i = 0; i < newNUM_CHAN; i++)
204 : {
205 22835 : if (newCHAN_WIDTH(i) < 0.)
206 : {
207 384 : negativeWidths = true;
208 384 : newCHAN_WIDTH(i) = -newCHAN_WIDTH(i);
209 : }
210 : }
211 233 : if (negativeWidths && verbose)
212 : {
213 6 : os << LogIO::NORMAL << LogOrigin("MSTransformRegridder", __FUNCTION__)
214 : << " *** Encountered negative channel widths in SPECTRAL_WINDOW table."
215 6 : << LogIO::POST;
216 3 : negChanWidthWarned = true;
217 : }
218 : }
219 :
220 : // Need to reverse the order for processing
221 233 : if (newIsDescending)
222 : {
223 6 : Vector<Double> tempF, tempW;
224 3 : tempF.assign(newCHAN_FREQ);
225 3 : tempW.assign(newCHAN_WIDTH);
226 387 : for (uInt i = 0; i < newNUM_CHAN; i++)
227 : {
228 384 : newCHAN_FREQ(i) = tempF(newNUM_CHAN - 1 - i);
229 384 : newCHAN_WIDTH(i) = tempW(newNUM_CHAN - 1 - i);
230 : }
231 : }
232 :
233 466 : Vector<Double> newEFFECTIVE_BW(effectiveBWColr(id0));
234 233 : Int newMEAS_FREQ_REF = measFreqRefColr(id0);
235 466 : Vector<Double> newRESOLUTION(resolutionColr(id0));
236 :
237 466 : vector<Int> averageN; // For each new channel store the number of old channels to average over
238 : //vector<vector<Int> > averageWhichSPW; // For each new channel store the (old) SPWs to average over
239 : //vector<vector<Int> > averageWhichChan; // For each new channel store the channel numbers to av. over
240 : //vector<vector<Double> > averageChanFrac; // For each new channel store the channel fraction for each old channel
241 :
242 : // Initialize the averaging vectors
243 23068 : for (uInt i = 0; i < newNUM_CHAN; i++)
244 : {
245 22835 : averageN.push_back(1);
246 45670 : vector<Int> tv; // Just a temporary auxiliary vector
247 22835 : tv.push_back(id0);
248 22835 : averageWhichSPW.push_back(tv);
249 22835 : if (newIsDescending)
250 : {
251 384 : tv[0] = newNUM_CHAN - 1 - i;
252 : }
253 : else
254 : {
255 22451 : tv[0] = i;
256 : }
257 22835 : averageWhichChan.push_back(tv);
258 45670 : vector<Double> tvd; // another one
259 22835 : tvd.push_back(1.);
260 22835 : averageChanFrac.push_back(tvd);
261 : }
262 :
263 233 : if (verbose)
264 : {
265 180 : os << LogIO::NORMAL << LogOrigin("MSTransformRegridder", __FUNCTION__)
266 : << "Input SPWs sorted by first (lowest) channel frequency:"
267 180 : << LogIO::POST;
268 :
269 90 : ostringstream oss; // needed for iomanip functions
270 90 : oss << " SPW " << std::setw(3) << id0 << ": " << std::setw(5)
271 90 : << newNUM_CHAN << " channels, first channel = "
272 90 : << std::setprecision(9) << std::setw(14) << std::scientific
273 90 : << newCHAN_FREQ(0) << " Hz";
274 90 : if (newNUM_CHAN > 1)
275 : {
276 : oss << ", last channel = " << std::setprecision(9)
277 78 : << std::setw(14) << std::scientific << newCHAN_FREQ(newNUM_CHAN - 1) << " Hz";
278 : }
279 180 : os << LogIO::NORMAL << LogOrigin("MSTransformRegridder", __FUNCTION__)
280 180 : << oss.str() << LogIO::POST;
281 : }
282 :
283 : // Loop over remaining given SPWs
284 1028 : for (uInt i = 1; i < nSpwsToCombine; i++)
285 : {
286 795 : Int idi = spwsSorted[i];
287 :
288 795 : uInt newNUM_CHANi = numChanColr(idi);
289 795 : Vector<Double> newCHAN_FREQi(chanFreqColr(idi));
290 795 : Vector<Double> newCHAN_WIDTHi(chanWidthColr(idi));
291 795 : Bool newIsDescendingI = isDescending(idi);
292 : {
293 795 : Bool negativeWidths = false;
294 75118 : for (uInt ii = 0; ii < newNUM_CHANi; ii++)
295 : {
296 74323 : if (newCHAN_WIDTHi(ii) < 0.)
297 : {
298 3200 : negativeWidths = true;
299 3200 : newCHAN_WIDTHi(ii) = -newCHAN_WIDTHi(ii);
300 : }
301 : }
302 795 : if (negativeWidths && !negChanWidthWarned && verbose)
303 : {
304 0 : os << LogIO::NORMAL << LogOrigin("MSTransformRegridder", __FUNCTION__)
305 : << " *** Encountered negative channel widths in SPECTRAL_WINDOW table."
306 0 : << LogIO::POST;
307 0 : negChanWidthWarned = true;
308 : }
309 : }
310 :
311 : // need to reverse the order for processing
312 795 : if (newIsDescendingI)
313 : {
314 50 : Vector<Double> tempF, tempW;
315 25 : tempF.assign(newCHAN_FREQi);
316 25 : tempW.assign(newCHAN_WIDTHi);
317 3225 : for (uInt ii = 0; ii < newNUM_CHANi; ii++)
318 : {
319 3200 : newCHAN_FREQi(ii) = tempF(newNUM_CHANi - 1 - ii);
320 3200 : newCHAN_WIDTHi(ii) = tempW(newNUM_CHANi - 1 - ii);
321 : }
322 : }
323 :
324 795 : Vector<Double> newEFFECTIVE_BWi(effectiveBWColr(idi));
325 795 : Int newMEAS_FREQ_REFi = measFreqRefColr(idi);
326 795 : Vector<Double> newRESOLUTIONi(resolutionColr(idi));
327 :
328 795 : if (verbose)
329 : {
330 534 : ostringstream oss;
331 534 : oss << " SPW " << std::setw(3) << idi << ": " << std::setw(5)
332 534 : << newNUM_CHANi << " channels, first channel = "
333 534 : << std::setprecision(9) << std::setw(14)
334 534 : << std::scientific << newCHAN_FREQi(0) << " Hz";
335 :
336 534 : if (newNUM_CHANi > 1)
337 : {
338 : oss << ", last channel = " << std::setprecision(9)
339 522 : << std::setw(14) << std::scientific
340 522 : << newCHAN_FREQi(newNUM_CHANi - 1) << " Hz";
341 : }
342 534 : os << LogIO::NORMAL << oss.str() << LogIO::POST;
343 : }
344 :
345 795 : vector<Double> mergedChanFreq;
346 795 : vector<Double> mergedChanWidth;
347 795 : vector<Double> mergedEffBW;
348 795 : vector<Double> mergedRes;
349 795 : vector<Int> mergedAverageN;
350 795 : vector<vector<Int> > mergedAverageWhichSPW;
351 795 : vector<vector<Int> > mergedAverageWhichChan;
352 795 : vector<vector<Double> > mergedAverageChanFrac;
353 :
354 : // check for compatibility
355 795 : if (newMEAS_FREQ_REFi != newMEAS_FREQ_REF)
356 : {
357 0 : os << LogIO::WARN << LogOrigin("MSTransformRegridder", __FUNCTION__)
358 : << "SPW " << idi
359 : << " cannot be combined with SPW " << id0
360 0 : << ". Non-matching ref. frame." << LogIO::POST;
361 0 : return false;
362 : }
363 :
364 : // Append or prepend spw to new spw overlap at all?
365 795 : if (newCHAN_FREQ(newNUM_CHAN - 1) + newCHAN_WIDTH(newNUM_CHAN - 1)
366 795 : / 2. < newCHAN_FREQi(0) - newCHAN_WIDTHi(0) / 2.)
367 : {
368 : // No overlap, and need to append
369 8862 : for (uInt j = 0; j < newNUM_CHAN; j++)
370 : {
371 8809 : mergedChanFreq.push_back(newCHAN_FREQ(j));
372 8809 : mergedChanWidth.push_back(newCHAN_WIDTH(j));
373 8809 : mergedEffBW.push_back(newEFFECTIVE_BW(j));
374 8809 : mergedRes.push_back(newRESOLUTION(j));
375 8809 : mergedAverageN.push_back(averageN[j]);
376 8809 : mergedAverageWhichSPW.push_back(averageWhichSPW[j]);
377 8809 : mergedAverageWhichChan.push_back(averageWhichChan[j]);
378 8809 : mergedAverageChanFrac.push_back(averageChanFrac[j]);
379 : }
380 :
381 106 : vector<Int> tv;
382 53 : tv.push_back(idi); // Origin is SPW Id-i
383 106 : vector<Int> tv2;
384 53 : tv2.push_back(0);
385 106 : vector<Double> tvd;
386 53 : tvd.push_back(1.); // Fraction is 1.
387 6235 : for (uInt j = 0; j < newNUM_CHANi; j++)
388 : {
389 6182 : mergedChanFreq.push_back(newCHAN_FREQi(j));
390 6182 : mergedChanWidth.push_back(newCHAN_WIDTHi(j));
391 6182 : mergedEffBW.push_back(newEFFECTIVE_BWi(j));
392 6182 : mergedRes.push_back(newRESOLUTIONi(j));
393 6182 : mergedAverageN.push_back(1); // so far only one channel
394 6182 : mergedAverageWhichSPW.push_back(tv);
395 6182 : if (newIsDescendingI)
396 : {
397 0 : tv2[0] = newNUM_CHANi - 1 - j;
398 : }
399 : else
400 : {
401 6182 : tv2[0] = j;
402 : }
403 6182 : mergedAverageWhichChan.push_back(tv2); // channel number is j
404 6182 : mergedAverageChanFrac.push_back(tvd);
405 : }
406 : }
407 742 : else if (newCHAN_FREQ(0) - newCHAN_WIDTH(0) / 2. > newCHAN_FREQi(
408 742 : newNUM_CHANi - 1) + newCHAN_WIDTHi(newNUM_CHANi - 1) / 2.)
409 : {
410 : // No overlap, need to prepend
411 0 : vector<Int> tv;
412 0 : tv.push_back(idi); // origin is SPW Id-i
413 0 : vector<Int> tv2;
414 0 : tv2.push_back(0);
415 0 : vector<Double> tvd;
416 0 : tvd.push_back(1.); // fraction is 1.
417 0 : for (uInt j = 0; j < newNUM_CHANi; j++)
418 : {
419 0 : mergedChanFreq.push_back(newCHAN_FREQi(j));
420 0 : mergedChanWidth.push_back(newCHAN_WIDTHi(j));
421 0 : mergedEffBW.push_back(newEFFECTIVE_BWi(j));
422 0 : mergedRes.push_back(newRESOLUTIONi(j));
423 0 : mergedAverageN.push_back(1); // so far only one channel
424 0 : mergedAverageWhichSPW.push_back(tv);
425 0 : if (newIsDescendingI)
426 : {
427 0 : tv2[0] = newNUM_CHANi - 1 - j;
428 : }
429 : else
430 : {
431 0 : tv2[0] = j;
432 : }
433 0 : mergedAverageWhichChan.push_back(tv2); // channel number is j
434 0 : mergedAverageChanFrac.push_back(tvd);
435 : }
436 :
437 0 : for (uInt j = 0; j < newNUM_CHAN; j++)
438 : {
439 0 : mergedChanFreq.push_back(newCHAN_FREQ(j));
440 0 : mergedChanWidth.push_back(newCHAN_WIDTH(j));
441 0 : mergedEffBW.push_back(newEFFECTIVE_BW(j));
442 0 : mergedRes.push_back(newRESOLUTION(j));
443 0 : mergedAverageN.push_back(averageN[j]);
444 0 : mergedAverageWhichSPW.push_back(averageWhichSPW[j]);
445 0 : mergedAverageWhichChan.push_back(averageWhichChan[j]);
446 0 : mergedAverageChanFrac.push_back(averageChanFrac[j]);
447 : }
448 : }
449 : // there is overlap
450 : else
451 : {
452 742 : Int id0StartChan = 0;
453 : // SPW Id-i starts before SPW Id-0
454 742 : if (newCHAN_FREQi(0) - newCHAN_WIDTHi(0) / 2. < newCHAN_FREQ(
455 742 : newNUM_CHAN - 1) - newCHAN_WIDTH(newNUM_CHAN - 1) / 2.)
456 : {
457 :
458 :
459 : // Some utilities for the averaging info
460 810 : vector<Int> tv; // temporary vector
461 405 : tv.push_back(idi); // origin is spw idi
462 810 : vector<Int> tv2;
463 405 : tv2.push_back(0);
464 810 : vector<Double> tvd;
465 405 : tvd.push_back(1.); // fraction is 1.
466 :
467 : // Find the first overlapping channel and prepend non-overlapping channels
468 405 : Double ubound0 = newCHAN_FREQ(0) + newCHAN_WIDTH(0) / 2.;
469 405 : Double lbound0 = newCHAN_FREQ(0) - newCHAN_WIDTH(0) / 2.;
470 405 : Double uboundk = 0.;
471 405 : Double lboundk = 0.;
472 : uInt k;
473 405 : for (k = 0; k < newNUM_CHANi; k++)
474 : {
475 405 : uboundk = newCHAN_FREQi(k) + newCHAN_WIDTHi(k) / 2.;
476 405 : lboundk = newCHAN_FREQi(k) - newCHAN_WIDTHi(k) / 2.;
477 405 : if (lbound0 < uboundk)
478 : {
479 405 : break;
480 : }
481 0 : mergedChanFreq.push_back(newCHAN_FREQi(k));
482 0 : mergedChanWidth.push_back(newCHAN_WIDTHi(k));
483 0 : mergedEffBW.push_back(newEFFECTIVE_BWi(k));
484 0 : mergedRes.push_back(newRESOLUTIONi(k));
485 0 : mergedAverageN.push_back(1); // So far only one channel
486 0 : mergedAverageWhichSPW.push_back(tv);
487 0 : if (newIsDescendingI)
488 : {
489 0 : tv2[0] = newNUM_CHANi - 1 - k;
490 : }
491 : else
492 : {
493 0 : tv2[0] = k;
494 : }
495 0 : mergedAverageWhichChan.push_back(tv2); // Channel number is k
496 0 : mergedAverageChanFrac.push_back(tvd);
497 : }
498 :
499 : // k-th is the one, actual overlap, need to merge channel k with channel 0
500 405 : if (lbound0 < uboundk && lboundk < lbound0)
501 : {
502 0 : Double newWidth = ubound0 - lboundk;
503 0 : Double newCenter = lboundk + newWidth / 2.;
504 0 : mergedChanFreq.push_back(newCenter);
505 0 : mergedChanWidth.push_back(newWidth);
506 0 : mergedEffBW.push_back(newWidth);
507 0 : mergedRes.push_back(newWidth);
508 0 : mergedAverageN.push_back(averageN[0] + 1); // one more channel contributes
509 :
510 : // Channel k is from SPW Id-i
511 0 : if (newIsDescendingI)
512 : {
513 0 : tv2[0] = newNUM_CHANi - 1 - k;
514 : }
515 : else
516 : {
517 0 : tv2[0] = k;
518 : }
519 :
520 0 : for (int j = 0; j < averageN[0]; j++)
521 : {
522 0 : tv.push_back(averageWhichSPW[0][j]); // additional contributors
523 0 : tv2.push_back(averageWhichChan[0][j]); // channel 0 from SPW Id-0
524 0 : tvd.push_back(averageChanFrac[0][j]);
525 : }
526 0 : mergedAverageWhichSPW.push_back(tv);
527 0 : mergedAverageWhichChan.push_back(tv2);
528 0 : mergedAverageChanFrac.push_back(tvd);
529 0 : id0StartChan = 1;
530 : }
531 : }
532 :
533 : // Now move along SPW id0 and merge until end of id0 is reached, then just copy
534 496607 : for (uInt j = id0StartChan; j < newNUM_CHAN; j++)
535 : {
536 495865 : mergedChanFreq.push_back(newCHAN_FREQ(j));
537 495865 : mergedChanWidth.push_back(newCHAN_WIDTH(j));
538 495865 : mergedEffBW.push_back(newEFFECTIVE_BW(j));
539 495865 : mergedRes.push_back(newRESOLUTION(j));
540 :
541 73000232 : for (uInt k = 0; k < newNUM_CHANi; k++)
542 : {
543 72504367 : Double overlap_frac = 0.;
544 :
545 : // Does channel j in SPW Id-0 overlap with channel k in SPW Id-i?
546 72504367 : Double uboundj = newCHAN_FREQ(j) + newCHAN_WIDTH(j)/ 2.;
547 72504367 : Double uboundk = newCHAN_FREQi(k) + newCHAN_WIDTHi(k)/ 2.;
548 72504367 : Double lboundj = newCHAN_FREQ(j) - newCHAN_WIDTH(j)/ 2.;
549 72504367 : Double lboundk = newCHAN_FREQi(k) - newCHAN_WIDTHi(k)/ 2.;
550 :
551 : // Determine fraction
552 :
553 : // Chan k is completely covered by chan j
554 72504367 : if (lboundj <= lboundk && uboundk <= uboundj)
555 : {
556 288 : overlap_frac = 1.;
557 : }
558 : // chan j is completely covered by chan k
559 72504079 : else if (lboundk <= lboundj && uboundj <= uboundk)
560 : {
561 0 : overlap_frac = newCHAN_WIDTH(j) / newCHAN_WIDTHi(k);
562 : }
563 : // lower end of k is overlapping with j
564 72504079 : else if (lboundj < lboundk && lboundk < uboundj && uboundj < uboundk)
565 : {
566 10686 : overlap_frac = (uboundj - lboundk) / newCHAN_WIDTHi(k);
567 : }
568 : // upper end of k is overlapping with j
569 72493393 : else if (lboundk < lboundj && lboundj < uboundk && lboundj < uboundk)
570 : {
571 10311 : overlap_frac = (uboundk - lboundj) / newCHAN_WIDTHi(k);
572 : }
573 :
574 : // Update averaging info
575 72504367 : if (overlap_frac > 0.)
576 : {
577 21285 : averageN[j] += 1;
578 21285 : averageWhichSPW[j].push_back(idi);
579 21285 : if (newIsDescendingI)
580 : {
581 1277 : averageWhichChan[j].push_back(newNUM_CHANi - 1 - k);
582 : }
583 : else
584 : {
585 20008 : averageWhichChan[j].push_back(k);
586 : }
587 21285 : averageChanFrac[j].push_back(overlap_frac);
588 : }
589 : } // End loop over SPW Id-i
590 :
591 :
592 : // Append this channel with updated averaging info
593 495865 : mergedAverageN.push_back(averageN[j]);
594 495865 : mergedAverageWhichSPW.push_back(averageWhichSPW[j]);
595 495865 : mergedAverageWhichChan.push_back(averageWhichChan[j]);
596 495865 : mergedAverageChanFrac.push_back(averageChanFrac[j]);
597 :
598 : } // End loop over SPW Id-0
599 :
600 : // SPW Id-i still continues, find the last overlapping channel
601 742 : if (newCHAN_FREQ(newNUM_CHAN - 1) + newCHAN_WIDTH(
602 742 : newNUM_CHAN - 1) / 2. < newCHAN_FREQi(newNUM_CHANi - 1)
603 742 : + newCHAN_WIDTHi(newNUM_CHANi - 1) / 2.)
604 : {
605 714 : Int j = newNUM_CHAN - 1;
606 714 : Double uboundj = newCHAN_FREQ(j) + newCHAN_WIDTH(j) / 2.;
607 714 : Double lboundj = newCHAN_FREQ(j) - newCHAN_WIDTH(j) / 2.;
608 714 : Double uboundk = 0;
609 714 : Double lboundk = 0;
610 : Int k;
611 57542 : for (k = newNUM_CHANi - 1; k >= 0; k--)
612 : {
613 57542 : uboundk = newCHAN_FREQi(k) + newCHAN_WIDTHi(k) / 2.;
614 57542 : lboundk = newCHAN_FREQi(k) - newCHAN_WIDTHi(k) / 2.;
615 57542 : if (lboundk <= uboundj)
616 : {
617 714 : break;
618 : }
619 : }
620 :
621 : // k-th is the one
622 :
623 : // actual overlap
624 714 : if (lboundk < uboundj && uboundj < uboundk)
625 : {
626 375 : Double overlap_frac = (uboundj - lboundk) / newCHAN_WIDTHi(k);
627 :
628 : // Merge channel k completely with channel j
629 375 : if (overlap_frac > 0.01)
630 : {
631 374 : Double newWidth = uboundk - lboundj;
632 374 : Double newCenter = (lboundj + uboundk) / 2.;
633 374 : mergedChanFreq[j] = newCenter;
634 374 : mergedChanWidth[j] = newWidth;
635 374 : mergedEffBW[j] = newWidth;
636 374 : mergedRes[j] = newWidth;
637 374 : mergedAverageChanFrac[j][mergedAverageN[j] - 1] = 1.;
638 : }
639 : // Create separate, (slightly) more narrow channel
640 : else
641 : {
642 1 : Double newWidth = uboundk - uboundj;
643 1 : Double newCenter = (uboundj + uboundk) / 2.;
644 2 : vector<Int> tv;
645 1 : tv.push_back(idi); // Origin is SPW Id-i
646 2 : vector<Int> tv2;
647 1 : tv2.push_back(0);
648 2 : vector<Double> tvd;
649 1 : tvd.push_back(1.); // Fraction is 1.
650 1 : mergedChanFreq.push_back(newCenter);
651 1 : mergedChanWidth.push_back(newWidth);
652 1 : mergedEffBW.push_back(newWidth);
653 1 : mergedRes.push_back(newWidth);
654 1 : mergedAverageN.push_back(1); // So far only one channel
655 1 : mergedAverageWhichSPW.push_back(tv);
656 1 : if (newIsDescendingI)
657 : {
658 0 : tv2[0] = newNUM_CHANi - 1 - k;
659 : }
660 : else
661 : {
662 1 : tv2[0] = k;
663 : }
664 1 : mergedAverageWhichChan.push_back(tv2); // Channel number is k
665 1 : mergedAverageChanFrac.push_back(tvd);
666 : }
667 :
668 375 : k++; // Start appending remaining channels after k
669 : }
670 :
671 : // Append the remaining channels
672 1428 : vector<Int> tv;
673 714 : tv.push_back(idi); // Origin is SPW Id-i
674 1428 : vector<Int> tv2;
675 714 : tv2.push_back(0);
676 1428 : vector<Double> tvd;
677 714 : tvd.push_back(1.); // Fraction is 1.
678 :
679 57881 : for (uInt m = k; m < newNUM_CHANi; m++)
680 : {
681 57167 : mergedChanFreq.push_back(newCHAN_FREQi(m));
682 57167 : mergedChanWidth.push_back(newCHAN_WIDTHi(m));
683 57167 : mergedEffBW.push_back(newEFFECTIVE_BWi(m));
684 57167 : mergedRes.push_back(newRESOLUTIONi(m));
685 57167 : mergedAverageN.push_back(1); // So far only one channel
686 57167 : mergedAverageWhichSPW.push_back(tv);
687 :
688 57167 : if (newIsDescendingI)
689 : {
690 2546 : tv2[0] = newNUM_CHANi - 1 - m;
691 : }
692 : else
693 : {
694 54621 : tv2[0] = m;
695 : }
696 57167 : mergedAverageWhichChan.push_back(tv2); // Channel number is m
697 57167 : mergedAverageChanFrac.push_back(tvd);
698 : }
699 : } // End if SPW Id-i still continues
700 : } // End if there is overlap
701 :
702 :
703 795 : newNUM_CHAN = mergedChanFreq.size();
704 795 : newCHAN_FREQ.assign(Vector<Double> (mergedChanFreq));
705 795 : newCHAN_WIDTH.assign(Vector<Double> (mergedChanWidth));
706 795 : newEFFECTIVE_BW.assign(Vector<Double> (mergedEffBW));
707 795 : newRESOLUTION.assign(Vector<Double> (mergedRes));
708 795 : averageN = mergedAverageN;
709 795 : averageWhichSPW.assign(mergedAverageWhichSPW.begin(), mergedAverageWhichSPW.end());
710 795 : averageChanFrac.assign(mergedAverageChanFrac.begin(), mergedAverageChanFrac.end());
711 795 : averageWhichChan.assign(mergedAverageWhichChan.begin(), mergedAverageWhichChan.end());
712 : }
713 :
714 233 : return true;
715 : }
716 :
717 : // -----------------------------------------------------------------------
718 : // A wrapper for regridChanBounds() which takes the user interface type re-gridding parameters
719 : // The ready-made grid is returned in newCHAN_FREQ and newCHAN_WIDTH
720 : // -----------------------------------------------------------------------
721 809 : Bool MSTransformRegridder::calcChanFreqs( LogIO& os,
722 : Vector<Double>& newCHAN_FREQ,
723 : Vector<Double>& newCHAN_WIDTH,
724 : Double& weightScale,
725 : const Vector<Double>& oldCHAN_FREQ,
726 : const Vector<Double>& oldCHAN_WIDTH,
727 : const MDirection phaseCenter,
728 : const MFrequency::Types theOldRefFrame,
729 : const MEpoch theObsTime,
730 : const MPosition mObsPos,
731 : const String& mode,
732 : const int nchan,
733 : const String& start,
734 : const String& width,
735 : const String& restfreq,
736 : const String& outframe,
737 : const String& veltype,
738 : const Bool verbose,
739 : const MRadialVelocity mRV)
740 : {
741 1618 : Vector<Double> newChanLoBound;
742 1618 : Vector<Double> newChanHiBound;
743 1618 : String t_phasec;
744 :
745 1618 : String t_mode;
746 1618 : String t_outframe;
747 1618 : String t_regridQuantity;
748 : Double t_restfreq;
749 1618 : String t_regridInterpMeth;
750 : Double t_cstart;
751 : Double t_bandwidth;
752 : Double t_cwidth;
753 : Bool t_centerIsStart;
754 : Bool t_startIsEnd;
755 : Int t_nchan;
756 : Int t_width;
757 : Int t_start;
758 :
759 809 : if (!convertGridPars(os, mode, nchan, start,width,
760 : "linear", // A dummy value in this context
761 : restfreq, outframe,veltype,
762 : ////// output ////
763 : t_mode, t_outframe, t_regridQuantity, t_restfreq,
764 : t_regridInterpMeth, t_cstart, t_bandwidth, t_cwidth,
765 : t_centerIsStart, t_startIsEnd, t_nchan, t_width, t_start))
766 : {
767 : // An error occurred
768 0 : return false;
769 : }
770 :
771 : // Reference frame transformation
772 809 : Bool needTransform = true;
773 809 : Bool doRadVelCorr = false;
774 : MFrequency::Types theFrame;
775 1618 : String oframe = outframe;
776 809 : oframe.upcase();
777 :
778 : // No output reference frame given
779 809 : if (outframe == "")
780 : {
781 : // Keep the reference frame as is
782 286 : theFrame = theOldRefFrame;
783 286 : needTransform = false;
784 : }
785 : // GEO transformation + radial velocity correction
786 523 : else if (oframe == "SOURCE")
787 : {
788 9 : theFrame = MFrequency::GEO;
789 9 : doRadVelCorr = true;
790 : }
791 514 : else if (!MFrequency::getType(theFrame, outframe))
792 : {
793 0 : os << LogIO::SEVERE << LogOrigin("MSTransformRegridder", __FUNCTION__)
794 0 : << "Parameter \"outframe\" value " << outframe << " is invalid." << LogIO::POST;
795 0 : return false;
796 : }
797 514 : else if (theFrame == theOldRefFrame)
798 : {
799 122 : needTransform = false;
800 : }
801 :
802 809 : uInt oldNUM_CHAN = oldCHAN_FREQ.size();
803 809 : if (oldNUM_CHAN == 0)
804 : {
805 0 : newCHAN_FREQ.resize(0);
806 0 : newCHAN_WIDTH.resize(0);
807 0 : return true;
808 : }
809 :
810 809 : if (oldNUM_CHAN != oldCHAN_WIDTH.size())
811 : {
812 0 : os << LogIO::SEVERE << LogOrigin("MSTransformRegridder", __FUNCTION__)
813 : << "Internal error: inconsistent dimensions of input channel frequency and width arrays."
814 0 : << LogIO::POST;
815 0 : return false;
816 : }
817 :
818 1618 : Vector<Double> absOldCHAN_WIDTH;
819 809 : absOldCHAN_WIDTH.assign(oldCHAN_WIDTH);
820 809 : Bool negativeWidths = false;
821 275113 : for (uInt i = 0; i < oldCHAN_WIDTH.size(); i++)
822 : {
823 274304 : if (oldCHAN_WIDTH(i) < 0.)
824 : {
825 24438 : negativeWidths = true;
826 24438 : absOldCHAN_WIDTH(i) = -oldCHAN_WIDTH(i);
827 : }
828 : }
829 :
830 809 : if (negativeWidths && verbose)
831 : {
832 62 : os << LogIO::NORMAL << LogOrigin("MSTransformRegridder", __FUNCTION__)
833 : << " *** Encountered negative channel widths in input spectral window."
834 62 : << LogIO::POST;
835 : }
836 :
837 1618 : Vector<Double> transNewXin;
838 1618 : Vector<Double> transCHAN_WIDTH(oldNUM_CHAN);
839 :
840 809 : if (needTransform)
841 : {
842 401 : transNewXin.resize(oldNUM_CHAN);
843 :
844 : // Set up conversion
845 802 : Unit unit(String("Hz"));
846 : MFrequency::Ref fromFrame = MFrequency::Ref(theOldRefFrame,
847 802 : MeasFrame(phaseCenter, mObsPos, theObsTime));
848 : MFrequency::Ref toFrame = MFrequency::Ref(theFrame,
849 802 : MeasFrame(phaseCenter, mObsPos, theObsTime));
850 802 : MFrequency::Convert freqTrans(unit, fromFrame, toFrame);
851 :
852 802 : MDoppler radVelCorr;
853 401 : Bool radVelSignificant = false;
854 :
855 : // Prepare correction for radial velocity if requested and possible
856 401 : if (doRadVelCorr)
857 : {
858 18 : Quantity mrv = mRV.get("m/s");
859 9 : radVelCorr = MDoppler(-mrv); // NOTE: Opposite sign to achieve correction!
860 9 : Double mRVVal = mrv.getValue();
861 9 : if (fabs(mRVVal) > 1E-6)
862 : {
863 5 : radVelSignificant = true;
864 : }
865 :
866 9 : if (verbose)
867 : {
868 10 : os << LogIO::NORMAL << LogOrigin("MSTransformRegridder", __FUNCTION__)
869 : << "Note: The given additional radial velocity of "
870 : << mRVVal << " m/s will be taken into account."
871 10 : << LogIO::POST;
872 : }
873 : }
874 :
875 107029 : for (uInt i = 0; i < oldNUM_CHAN; i++)
876 : {
877 106628 : transNewXin[i] = freqTrans(oldCHAN_FREQ[i]).get(unit).getValue();
878 :
879 : // eliminate possible offsets
880 106628 : transCHAN_WIDTH[i] = freqTrans(oldCHAN_FREQ[i] + absOldCHAN_WIDTH[i] / 2.).
881 213256 : get(unit).getValue() - freqTrans(oldCHAN_FREQ[i] - absOldCHAN_WIDTH[i] / 2.).
882 106628 : get(unit).getValue();
883 : }
884 :
885 : // Correct in addition for radial velocity
886 401 : if (radVelSignificant)
887 : {
888 5 : transNewXin = radVelCorr.shiftFrequency(transNewXin);
889 :
890 : //shiftFrequency is a scaling, so channel widths scale as well
891 5 : transCHAN_WIDTH = radVelCorr.shiftFrequency(transCHAN_WIDTH);
892 : }
893 :
894 : }
895 : else
896 : {
897 : // Just copy
898 408 : transNewXin.assign(oldCHAN_FREQ);
899 408 : transCHAN_WIDTH.assign(absOldCHAN_WIDTH);
900 : }
901 :
902 : // Calculate new grid
903 :
904 1618 : String message;
905 :
906 809 : if (!regridChanBounds( newChanLoBound, newChanHiBound, t_cstart,
907 : t_bandwidth, t_cwidth, t_restfreq, t_regridQuantity, transNewXin,
908 : transCHAN_WIDTH, message, t_centerIsStart, t_startIsEnd, t_nchan,
909 : t_width, t_start))
910 : {
911 : // There was an error
912 2 : os << LogIO::WARN << LogOrigin("MSTransformRegridder", __FUNCTION__) << message << LogIO::POST;
913 2 : return false;
914 : }
915 :
916 807 : if (verbose)
917 : {
918 619 : os << LogIO::NORMAL << LogOrigin("MSTransformRegridder", __FUNCTION__) << message << LogIO::POST;
919 : }
920 :
921 : // We have a useful set of channel boundaries
922 807 : uInt newNUM_CHAN = newChanLoBound.size();
923 :
924 : // Complete the calculation of the new channel centers and widths
925 : // from newNUM_CHAN, newChanLoBound, and newChanHiBound
926 807 : newCHAN_FREQ.resize(newNUM_CHAN);
927 807 : newCHAN_WIDTH.resize(newNUM_CHAN);
928 177735 : for (uInt i = 0; i < newNUM_CHAN; i++)
929 : {
930 176928 : newCHAN_FREQ[i] = (newChanLoBound[i] + newChanHiBound[i]) / 2.;
931 176928 : newCHAN_WIDTH[i] = newChanHiBound[i] - newChanLoBound[i];
932 : }
933 :
934 807 : weightScale = newCHAN_WIDTH[0]/transCHAN_WIDTH[0];
935 :
936 807 : return true;
937 : }
938 :
939 : // -----------------------------------------------------------------------
940 : // Helper function for handling the re-gridding parameter user input
941 : // -----------------------------------------------------------------------
942 809 : Bool MSTransformRegridder::convertGridPars( LogIO& os,
943 : const String& mode,
944 : const int nchan,
945 : const String& start,
946 : const String& width,
947 : const String& interp,
948 : const String& restfreq,
949 : const String& outframe,
950 : const String& veltype,
951 : String& t_mode,
952 : String& t_outframe,
953 : String& t_regridQuantity,
954 : Double& t_restfreq,
955 : String& t_regridInterpMeth,
956 : Double& t_cstart,
957 : Double& t_bandwidth,
958 : Double& t_cwidth,
959 : Bool& t_centerIsStart,
960 : Bool& t_startIsEnd,
961 : Int& t_nchan,
962 : Int& t_width,
963 : Int& t_start)
964 : {
965 809 : Bool rstat(false);
966 :
967 : try {
968 :
969 809 : casacore::QuantumHolder qh;
970 809 : String error;
971 :
972 809 : t_mode = mode;
973 809 : t_restfreq = 0.;
974 809 : if (!restfreq.empty() && !(restfreq == "[]"))
975 : {
976 471 : if (qh.fromString(error, restfreq))
977 : {
978 471 : t_restfreq = qh.asQuantity().getValue("Hz");
979 : }
980 : else
981 : {
982 0 : os << LogIO::SEVERE << LogOrigin("MSTransformRegridder", __FUNCTION__)
983 0 : << "restfreq: " << error << LogIO::POST;
984 0 : return false;
985 : }
986 : }
987 :
988 : // Determine grid
989 809 : t_cstart = -9e99; // Default value indicating that the original start of the SPW should be used
990 809 : t_bandwidth = -1.; // Default value indicating that the original width of the SPW should be used
991 809 : t_cwidth = -1.; // Default value indicating that the original channel width of the SPW should be used
992 809 : t_nchan = -1;
993 809 : t_width = 0;
994 809 : t_start = -1;
995 809 : t_startIsEnd = false; // false means that start specifies the lower end in frequency (default)
996 : // true means that start specifies the upper end in frequency
997 :
998 : // start was set
999 809 : if (!start.empty() && !(start == "[]"))
1000 : {
1001 780 : if (t_mode == "channel")
1002 : {
1003 683 : t_start = atoi(start.c_str());
1004 : }
1005 780 : if (t_mode == "channel_b")
1006 : {
1007 2 : t_cstart = Double(atoi(start.c_str()));
1008 : }
1009 778 : else if (t_mode == "frequency")
1010 : {
1011 63 : if (qh.fromString(error, start))
1012 : {
1013 63 : t_cstart = qh.asQuantity().getValue("Hz");
1014 : }
1015 : else
1016 : {
1017 0 : os << LogIO::SEVERE << LogOrigin("MSTransformRegridder", __FUNCTION__)
1018 0 : << "start: " << error << LogIO::POST;
1019 0 : return false;
1020 : }
1021 : }
1022 715 : else if (t_mode == "velocity")
1023 : {
1024 32 : if (qh.fromString(error, start))
1025 : {
1026 32 : t_cstart = qh.asQuantity().getValue("m/s");
1027 : }
1028 : else
1029 : {
1030 0 : os << LogIO::SEVERE << LogOrigin("MSTransformRegridder", __FUNCTION__)
1031 0 : << "start: " << error << LogIO::POST;
1032 0 : return false;
1033 : }
1034 : }
1035 : }
1036 :
1037 : // channel width was set
1038 809 : if (!width.empty() && !(width == "[]"))
1039 : {
1040 780 : if (t_mode == "channel")
1041 : {
1042 683 : Int w = atoi(width.c_str());
1043 683 : t_width = abs(w);
1044 683 : if (w < 0)
1045 : {
1046 4 : t_startIsEnd = true;
1047 : }
1048 : }
1049 97 : else if (t_mode == "channel_b")
1050 : {
1051 2 : Double w = atoi(width.c_str());
1052 2 : t_cwidth = abs(w);
1053 2 : if (w < 0)
1054 : {
1055 1 : t_startIsEnd = true;
1056 : }
1057 : }
1058 95 : else if (t_mode == "frequency")
1059 : {
1060 59 : if (qh.fromString(error, width))
1061 : {
1062 59 : Double w = qh.asQuantity().getValue("Hz");
1063 59 : t_cwidth = abs(w);
1064 59 : if (w < 0)
1065 : {
1066 8 : t_startIsEnd = true;
1067 : }
1068 : }
1069 : else
1070 : {
1071 0 : os << LogIO::SEVERE << LogOrigin("MSTransformRegridder", __FUNCTION__)
1072 0 : << "width: " << error << LogIO::POST;
1073 0 : return false;
1074 : }
1075 : }
1076 36 : else if (t_mode == "velocity")
1077 : {
1078 36 : if (qh.fromString(error, width))
1079 : {
1080 36 : Double w = qh.asQuantity().getValue("m/s");
1081 36 : t_cwidth = abs(w);
1082 36 : if (w >= 0)
1083 : {
1084 27 : t_startIsEnd = true;
1085 : }
1086 : }
1087 : else
1088 : {
1089 0 : os << LogIO::SEVERE << LogOrigin("MSTransformRegridder", __FUNCTION__)
1090 0 : << "width: " << error << LogIO::POST;
1091 0 : return false;
1092 : }
1093 : }
1094 : }
1095 : // width was not set
1096 : else
1097 : {
1098 : // For the velocity mode the default t_startIsEnd is true if the sign of width is not known
1099 29 : if (t_mode == "velocity")
1100 : {
1101 15 : t_startIsEnd = true;
1102 : }
1103 : }
1104 :
1105 : // Number of output channels was set
1106 809 : if (nchan > 0)
1107 : {
1108 257 : if (t_mode == "channel_b")
1109 : {
1110 1 : if (t_cwidth > 0)
1111 : {
1112 1 : t_bandwidth = Double(nchan * t_cwidth);
1113 : }
1114 : else
1115 : {
1116 0 : t_bandwidth = Double(nchan);
1117 : }
1118 : }
1119 : else
1120 : {
1121 256 : t_nchan = nchan;
1122 : }
1123 : }
1124 :
1125 809 : if (t_mode == "channel")
1126 : {
1127 683 : t_regridQuantity = "freq";
1128 : }
1129 126 : else if (t_mode == "channel_b")
1130 : {
1131 2 : t_regridQuantity = "chan";
1132 : }
1133 124 : else if (t_mode == "frequency")
1134 : {
1135 73 : t_regridQuantity = "freq";
1136 : }
1137 51 : else if (t_mode == "velocity")
1138 : {
1139 51 : if (t_restfreq == 0.)
1140 : {
1141 0 : os << LogIO::SEVERE << LogOrigin("MSTransformRegridder", __FUNCTION__)
1142 : << "Need to set restfreq in velocity mode."
1143 0 : << LogIO::POST;
1144 0 : return false;
1145 : }
1146 :
1147 51 : t_regridQuantity = "vrad";
1148 51 : if (veltype == "optical")
1149 : {
1150 8 : t_regridQuantity = "vopt";
1151 : }
1152 43 : else if (veltype != "radio")
1153 : {
1154 4 : os << LogIO::WARN << LogOrigin("MSTransformRegridder", __FUNCTION__)
1155 : << "Invalid velocity type " << veltype
1156 4 : << ", setting type to \"radio\"" << LogIO::POST;
1157 : }
1158 :
1159 : }
1160 : else
1161 : {
1162 0 : os << LogIO::WARN << LogOrigin("MSTransformRegridder", __FUNCTION__)
1163 0 : << "Invalid mode " << t_mode << LogIO::POST;
1164 0 : return false;
1165 : }
1166 :
1167 809 : t_outframe = outframe;
1168 809 : t_regridInterpMeth = interp;
1169 809 : t_centerIsStart = true;
1170 :
1171 : // End prepare re-gridding parameters
1172 809 : rstat = true;
1173 :
1174 : }
1175 0 : catch (AipsError x)
1176 : {
1177 0 : os << LogIO::SEVERE << LogOrigin("MSTransformRegridder", __FUNCTION__)
1178 0 : << "Exception Reported: " << x.getMesg() << LogIO::POST;
1179 0 : rstat = false;
1180 : }
1181 :
1182 809 : return rstat;
1183 : }
1184 :
1185 : // -----------------------------------------------------------------------
1186 : // Calculate the final new channel boundaries from the re-regridding parameters and
1187 : // the old channel boundaries (already transformed to the desired reference frame).
1188 : // Returns false if input parameters were invalid and no useful boundaries could be created
1189 : // -----------------------------------------------------------------------
1190 809 : Bool MSTransformRegridder::regridChanBounds( Vector<Double>& newChanLoBound,
1191 : Vector<Double>& newChanHiBound,
1192 : const Double regridCenterC,
1193 : const Double regridBandwidth,
1194 : const Double regridChanWidthC,
1195 : const Double regridVeloRestfrq,
1196 : const String regridQuant,
1197 : const Vector<Double>& transNewXinC,
1198 : const Vector<Double>& transCHAN_WIDTHC,
1199 : String& message,
1200 : const Bool centerIsStartC,
1201 : const Bool startIsEndC,
1202 : const Int nchanC,
1203 : const Int width,
1204 : const Int startC)
1205 : {
1206 1618 : ostringstream oss;
1207 :
1208 1618 : Vector<Double> transNewXin(transNewXinC);
1209 1618 : Vector<Double> transCHAN_WIDTH(transCHAN_WIDTHC);
1210 809 : Bool centerIsStart = centerIsStartC;
1211 809 : Bool startIsEnd = startIsEndC;
1212 809 : Double regridChanWidth = regridChanWidthC;
1213 809 : Double regridCenter = regridCenterC;
1214 809 : Int nchan = nchanC;
1215 809 : Int start = startC;
1216 :
1217 809 : Int oldNUM_CHAN = transNewXin.size();
1218 :
1219 : // Detect spectral windows defined with descending frequency
1220 809 : Bool isDescending = false;
1221 274304 : for (uInt i = 1; i < transNewXin.size(); i++)
1222 : {
1223 273495 : if (transNewXin(i) < transNewXin(i - 1))
1224 : {
1225 24396 : isDescending = true;
1226 : }
1227 : // i.e. descending was detected but now we encounter ascending
1228 249099 : else if (isDescending)
1229 : {
1230 0 : oss << "Channel frequencies are neither in ascending nor in descending order. Cannot process.";
1231 0 : message = oss.str();
1232 0 : return false;
1233 : }
1234 : }
1235 :
1236 : // Need to reverse the order for processing and later reverse the result
1237 809 : if (isDescending)
1238 : {
1239 36 : uInt n = transNewXin.size();
1240 72 : Vector<Double> tempF, tempW;
1241 36 : tempF.assign(transNewXin);
1242 36 : tempW.assign(transCHAN_WIDTH);
1243 24468 : for (uInt i = 0; i < n; i++)
1244 : {
1245 24432 : transNewXin(i) = tempF(n - 1 - i);
1246 24432 : transCHAN_WIDTH(i) = tempW(n - 1 - i);
1247 : }
1248 :
1249 : // Also need to adjust the start values
1250 36 : if (startC >= 0)
1251 : {
1252 22 : start = n - 1 - startC;
1253 22 : if (centerIsStartC)
1254 : {
1255 22 : startIsEnd = !startIsEnd;
1256 : }
1257 : }
1258 : }
1259 :
1260 : // Verify regridCenter, regridBandwidth, and regridChanWidth
1261 : // Note: these are in the units corresponding to regridQuant!
1262 :
1263 809 : if (regridQuant == "chan")
1264 : {
1265 : // Channel numbers ...
1266 2 : Int regridCenterChan = -1;
1267 2 : Int regridBandwidthChan = -1;
1268 2 : Int regridChanWidthChan = -1;
1269 :
1270 : // Not set
1271 2 : if (regridCenter < -1E30)
1272 : {
1273 : // Find channel center closest to center of bandwidth
1274 0 : lDouble BWCenterF = (transNewXin[0] + transNewXin[oldNUM_CHAN - 1]) / 2.;
1275 0 : for (Int i = 0; i < oldNUM_CHAN; i++)
1276 : {
1277 0 : if (transNewXin[i] >= BWCenterF)
1278 : {
1279 0 : regridCenterChan = i;
1280 0 : break;
1281 : }
1282 : }
1283 0 : centerIsStart = false;
1284 : }
1285 : // Valid input
1286 2 : else if (0. <= regridCenter && regridCenter < Double(oldNUM_CHAN))
1287 : {
1288 2 : regridCenterChan = (Int) floor(regridCenter);
1289 : }
1290 : // Invalid
1291 : else
1292 : {
1293 0 : if (centerIsStart)
1294 : {
1295 0 : oss << "SPW start ";
1296 : }
1297 : else
1298 : {
1299 0 : oss << "SPW center ";
1300 : }
1301 0 : oss << regridCenter << " outside valid range which is " << 0 << " - " << oldNUM_CHAN - 1 << ".";
1302 0 : message = oss.str();
1303 0 : return false;
1304 : }
1305 :
1306 : // Not set or nchan set
1307 2 : if (regridBandwidth <= 0. || nchan > 0)
1308 : {
1309 2 : if (nchan > 0)
1310 : {
1311 0 : regridBandwidthChan = nchan;
1312 : }
1313 : else
1314 : {
1315 1 : regridBandwidthChan = oldNUM_CHAN;
1316 : }
1317 : }
1318 : else
1319 : {
1320 1 : regridBandwidthChan = (Int) floor(regridBandwidth);
1321 : }
1322 :
1323 2 : if (centerIsStart)
1324 : {
1325 2 : if (startIsEnd)
1326 : {
1327 1 : regridCenterChan = regridCenterChan - regridBandwidthChan / 2;
1328 : }
1329 : else
1330 : {
1331 1 : regridCenterChan = regridCenterChan + regridBandwidthChan / 2;
1332 : }
1333 2 : centerIsStart = false;
1334 : }
1335 :
1336 : // Center too close to lower edge
1337 2 : if (regridCenterChan - regridBandwidthChan / 2 < 0)
1338 : {
1339 0 : regridBandwidthChan = 2 * regridCenterChan + 1;
1340 0 : oss << " *** Requested output SPW width too large." << endl;
1341 : }
1342 : // Center too close to upper edge
1343 2 : if (oldNUM_CHAN < regridCenterChan + regridBandwidthChan / 2)
1344 : {
1345 0 : regridBandwidthChan = 2 * (oldNUM_CHAN - regridCenterChan);
1346 0 : oss << " *** Requested output SPW width too large." << endl;
1347 : }
1348 :
1349 2 : if (regridChanWidth < 1.)
1350 : {
1351 0 : regridChanWidthChan = 1;
1352 : }
1353 2 : else if (regridChanWidth > Double(regridBandwidthChan))
1354 : {
1355 0 : regridChanWidthChan = regridBandwidthChan; // i.e. SPW = a single channel
1356 0 : oss << " *** Requested output channel width too large. Adjusted to maximum possible value." << endl;
1357 : }
1358 : // Valid input
1359 : else
1360 : {
1361 2 : regridChanWidthChan = (Int) floor(regridChanWidth);
1362 2 : if (nchan > 0)
1363 : {
1364 0 : regridBandwidthChan = nchan * regridChanWidthChan;
1365 : }
1366 : }
1367 :
1368 2 : if (regridBandwidthChan != floor(regridBandwidth))
1369 : {
1370 1 : oss << " *** Output SPW width set to " << regridBandwidthChan << " original channels" << endl;
1371 1 : oss << " in an attempt to keep center of output SPW close to center of requested SPW." << endl;
1372 : }
1373 :
1374 : // Calculate newChanLoBound and newChanHiBound from
1375 : // regridCenterChan, regridBandwidthChan, and regridChanWidthChan
1376 2 : Int bwLowerEndChan = regridCenterChan - regridBandwidthChan / 2;
1377 2 : Int bwUpperEndChan = bwLowerEndChan + regridBandwidthChan - 1;
1378 2 : Int numNewChanDown = 0;
1379 2 : Int numNewChanUp = 0;
1380 :
1381 : // Only one new channel
1382 2 : if (regridChanWidthChan == regridBandwidthChan)
1383 : {
1384 0 : newChanLoBound.resize(1);
1385 0 : newChanHiBound.resize(1);
1386 0 : newChanLoBound[0] = transNewXin[bwLowerEndChan] - transCHAN_WIDTH[bwLowerEndChan] / 2.;
1387 0 : newChanHiBound[0] = transNewXin[bwUpperEndChan] + transCHAN_WIDTH[bwUpperEndChan] / 2.;
1388 0 : numNewChanUp = 1;
1389 : }
1390 : // Have more than one new channel
1391 : else
1392 : {
1393 : // Need to accommodate the possibility that the original channels are not contiguous!
1394 :
1395 : // The numbers of the Channels from which the lower bounds will be taken for the new channels
1396 4 : vector<Int> loNCBup;
1397 : // Starting from the central channel going up
1398 4 : vector<Int> hiNCBup; // The numbers of the Channels from which the high
1399 : // Bounds will be taken for the new channels starting from the central channel going up
1400 4 : vector<Int> loNCBdown; // The numbers of the Channels from which the
1401 : // Lower bounds will be taken for the new channels starting from the central channel going down
1402 4 : vector<Int> hiNCBdown; // The numbers of the Channels from which the high bounds will be taken
1403 : // for the new channels starting from the central channel going down.
1404 : // Want to keep the center of the center channel at the center of the new center
1405 : // channel if the bandwidth is an odd multiple of the new channel width
1406 : // otherwise the center channel is the lower edge of the new center channel
1407 : Int startChan;
1408 2 : lDouble tnumChan = regridBandwidthChan / regridChanWidthChan;
1409 2 : if ((Int) tnumChan % 2 != 0)
1410 : {
1411 : // Odd multiple
1412 1 : startChan = regridCenterChan - regridChanWidthChan / 2;
1413 : }
1414 : else
1415 : {
1416 1 : startChan = regridCenterChan;
1417 : }
1418 :
1419 : // Upper half
1420 1219 : for (Int i = startChan; i <= bwUpperEndChan; i += regridChanWidthChan)
1421 : {
1422 1217 : loNCBup.push_back(i);
1423 1217 : if (i + regridChanWidthChan - 1 <= bwUpperEndChan)
1424 : {
1425 : // Can go one more normal step up
1426 1217 : hiNCBup.push_back(i + regridChanWidthChan - 1);
1427 : }
1428 : else
1429 : {
1430 : // Create narrower channels at the edges if necessary
1431 0 : oss << " *** Last channel at upper edge of new SPW made only "
1432 0 : << bwUpperEndChan - i + 1
1433 0 : << " original channels wide to fit given total bandwidth."
1434 0 : << endl;
1435 0 : hiNCBup.push_back(bwUpperEndChan);
1436 : }
1437 : }
1438 :
1439 : // Lower half
1440 1218 : for (Int i = startChan - 1; i >= bwLowerEndChan; i -= regridChanWidthChan)
1441 : {
1442 1216 : hiNCBdown.push_back(i);
1443 1216 : if (i - regridChanWidthChan + 1 >= bwLowerEndChan)
1444 : {
1445 : // Can go one more normal step down
1446 1216 : loNCBdown.push_back(i - regridChanWidthChan + 1);
1447 : }
1448 : else
1449 : {
1450 : // Create narrower channels at the edges if necessary
1451 0 : oss << " *** First channel at lower edge of new SPW made only "
1452 0 : << i - bwLowerEndChan + 1
1453 0 : << " original channels wide to fit given total bandwidth."
1454 0 : << endl;
1455 0 : loNCBdown.push_back(bwLowerEndChan);
1456 : }
1457 : }
1458 :
1459 : // The number of channels below the central one
1460 2 : numNewChanDown = loNCBdown.size();
1461 :
1462 : // The number of channels above and including the central one
1463 2 : numNewChanUp = loNCBup.size();
1464 :
1465 2 : newChanLoBound.resize(numNewChanDown + numNewChanUp);
1466 2 : newChanHiBound.resize(numNewChanDown + numNewChanUp);
1467 1218 : for (Int i = 0; i < numNewChanDown; i++)
1468 : {
1469 1216 : Int k = numNewChanDown - i - 1; // Need to assign in reverse
1470 1216 : newChanLoBound[i] = transNewXin[loNCBdown[k]] - transCHAN_WIDTH[loNCBdown[k]] / 2.;
1471 1216 : newChanHiBound[i] = transNewXin[hiNCBdown[k]] + transCHAN_WIDTH[hiNCBdown[k]] / 2.;
1472 : }
1473 :
1474 1219 : for (Int i = 0; i < numNewChanUp; i++)
1475 : {
1476 1217 : newChanLoBound[i + numNewChanDown] = transNewXin[loNCBup[i]] - transCHAN_WIDTH[loNCBup[i]] / 2.;
1477 1217 : newChanHiBound[i + numNewChanDown] = transNewXin[hiNCBup[i]] + transCHAN_WIDTH[hiNCBup[i]] / 2.;
1478 : }
1479 : } // end if
1480 :
1481 2 : oss << " New channels defined based on original channels" << endl
1482 2 : << " Central channel contains original channel "
1483 2 : << regridCenterChan << endl << " Channel width = "
1484 2 : << regridChanWidthChan << " original channels" << endl
1485 2 : << " Total width of SPW = " << regridBandwidthChan
1486 2 : << " original channels == " << numNewChanDown + numNewChanUp
1487 2 : << " new channels" << endl;
1488 :
1489 2 : uInt nc = newChanLoBound.size();
1490 2 : oss << " Total width of SPW (in output frame) = "
1491 2 : << newChanHiBound[nc- 1] - newChanLoBound[0] << " Hz" << endl;
1492 2 : oss << " Lower edge = " << std::setprecision(9) << newChanLoBound[0] << " Hz,"
1493 2 : << " upper edge = " << std::setprecision(9) << newChanHiBound[nc - 1] << " Hz" << endl;
1494 :
1495 2 : if (isDescending)
1496 : {
1497 0 : Vector<Double> tempL, tempU;
1498 0 : tempL.assign(newChanLoBound);
1499 0 : tempU.assign(newChanHiBound);
1500 0 : for (uInt i = 0; i < nc; i++)
1501 : {
1502 0 : newChanLoBound(i) = tempL(nc - 1 - i);
1503 0 : newChanHiBound(i) = tempU(nc - 1 - i);
1504 : }
1505 : }
1506 :
1507 2 : message = oss.str();
1508 :
1509 2 : return true;
1510 : }
1511 : // We operate on real numbers /////////////////
1512 : else
1513 : {
1514 : // First transform them to frequencies
1515 807 : lDouble regridCenterF = -1.; // Initialize as "not set"
1516 807 : lDouble regridBandwidthF = -1.;
1517 807 : lDouble regridChanWidthF = -1.;
1518 :
1519 807 : if (regridQuant == "vrad")
1520 : {
1521 : // radio velocity need restfrq
1522 43 : if (regridVeloRestfrq < -1E30) // means "not set"
1523 : {
1524 0 : oss << "Parameter \"restfreq\" needs to be set if regrid_quantity==vrad. Cannot proceed with regridSpw ...";
1525 0 : message = oss.str();
1526 0 : return false;
1527 : }
1528 43 : else if (regridVeloRestfrq < 0. || regridVeloRestfrq > 1E30)
1529 : {
1530 0 : oss << "Parameter \"restfreq\" value " << regridVeloRestfrq << " is invalid.";
1531 0 : message = oss.str();
1532 0 : return false;
1533 : }
1534 :
1535 : lDouble regridCenterVel;
1536 43 : if (regridCenter > -C::c)
1537 : {
1538 : // (We deal with invalid values later)
1539 26 : if (centerIsStart)
1540 : {
1541 : Double tcWidth;
1542 26 : if (regridChanWidth > 0.)
1543 : {
1544 15 : tcWidth = regridChanWidth;
1545 : }
1546 : else
1547 : {
1548 11 : tcWidth = vrad( transNewXin[0] - transCHAN_WIDTH[0] / 2.,
1549 11 : regridVeloRestfrq) - vrad(
1550 11 : transNewXin[0] + transCHAN_WIDTH[0] / 2.,
1551 : regridVeloRestfrq);
1552 : }
1553 :
1554 : // start is the center of the last channel (in freq)
1555 26 : if (startIsEnd)
1556 : {
1557 21 : regridCenter -= tcWidth / 2.;
1558 : }
1559 : // start is the center of the first channel (in freq)
1560 : else
1561 : {
1562 5 : regridCenter += tcWidth / 2.;
1563 : }
1564 : }
1565 :
1566 26 : regridCenterF = freq_from_vrad(regridCenter, regridVeloRestfrq);
1567 :
1568 26 : regridCenterVel = regridCenter;
1569 : }
1570 : // center was not specified
1571 : else
1572 : {
1573 17 : regridCenterF = (transNewXin[0] + transNewXin[oldNUM_CHAN - 1])/ 2.;
1574 17 : regridCenterVel = vrad(regridCenterF, regridVeloRestfrq);
1575 17 : centerIsStart = false;
1576 : }
1577 43 : if (nchan > 0)
1578 : {
1579 38 : if (regridChanWidth > 0.)
1580 : {
1581 25 : lDouble chanUpperEdgeF = freq_from_vrad(regridCenterVel - regridChanWidth / 2.,regridVeloRestfrq);
1582 25 : regridChanWidthF = 2. * (chanUpperEdgeF - regridCenterF);
1583 : }
1584 : // take channel width from first channel
1585 : else
1586 : {
1587 13 : regridChanWidthF = transCHAN_WIDTH[0];
1588 : }
1589 :
1590 38 : regridBandwidthF = nchan * regridChanWidthF;
1591 : // Can convert start to center
1592 38 : if (centerIsStart)
1593 : {
1594 26 : if (startIsEnd)
1595 : {
1596 21 : regridCenterF = regridCenterF - regridBandwidthF / 2.;
1597 : }
1598 : else
1599 : {
1600 5 : regridCenterF = regridCenterF + regridBandwidthF / 2.;
1601 : }
1602 26 : centerIsStart = false;
1603 : }
1604 : }
1605 5 : else if (regridBandwidth > 0.)
1606 : {
1607 : // Can convert start to center
1608 0 : if (centerIsStart)
1609 : {
1610 0 : if (startIsEnd)
1611 : {
1612 0 : regridCenterVel = regridCenter + regridBandwidth / 2.;
1613 : }
1614 : else
1615 : {
1616 0 : regridCenterVel = regridCenter - regridBandwidth / 2.;
1617 : }
1618 0 : regridCenterF = freq_from_vrad(regridCenterVel,regridVeloRestfrq);
1619 0 : centerIsStart = false;
1620 : }
1621 0 : lDouble bwUpperEndF = freq_from_vrad(regridCenterVel - regridBandwidth / 2.,regridVeloRestfrq);
1622 0 : regridBandwidthF = 2. * (bwUpperEndF - regridCenterF);
1623 : }
1624 :
1625 43 : if (regridChanWidth > 0. && regridChanWidthF < 0.)
1626 : {
1627 4 : lDouble chanUpperEdgeF = freq_from_vrad(regridCenterVel - regridChanWidth / 2.,regridVeloRestfrq);
1628 4 : regridChanWidthF = 2. * (chanUpperEdgeF - freq_from_vrad(regridCenterVel, regridVeloRestfrq));
1629 : }
1630 : }
1631 764 : else if (regridQuant == "vopt")
1632 : {
1633 : // Optical velocity need restfrq
1634 8 : if (regridVeloRestfrq < -1E30) // means "not set"
1635 : {
1636 0 : oss << "Parameter \"restfreq\" needs to be set if regrid_quantity==vopt. Cannot proceed with regridSpw ...";
1637 0 : message = oss.str();
1638 0 : return false;
1639 : }
1640 8 : else if (regridVeloRestfrq <= 0. || regridVeloRestfrq > 1E30)
1641 : {
1642 0 : oss << "Parameter \"restfreq\" value " << regridVeloRestfrq << " is invalid.";
1643 0 : message = oss.str();
1644 0 : return false;
1645 : }
1646 :
1647 : lDouble regridCenterVel;
1648 8 : if (regridCenter > -C::c)
1649 : {
1650 6 : if (centerIsStart)
1651 : {
1652 : Double tcWidth;
1653 6 : if (regridChanWidth > 0.)
1654 : {
1655 6 : tcWidth = regridChanWidth;
1656 : }
1657 : else
1658 : {
1659 0 : tcWidth = vopt( transNewXin[0] - transCHAN_WIDTH[0] / 2.,
1660 0 : regridVeloRestfrq) - vopt(
1661 0 : transNewXin[0] + transCHAN_WIDTH[0] / 2.,
1662 : regridVeloRestfrq);
1663 : }
1664 :
1665 : // start is the center of the last channel (in freq)
1666 6 : if (startIsEnd)
1667 : {
1668 5 : regridCenter -= tcWidth / 2.;
1669 : }
1670 : // start is the center of the first channel (in freq)
1671 : else
1672 : {
1673 1 : regridCenter += tcWidth / 2.;
1674 : }
1675 : }
1676 :
1677 : // (We deal with invalid values later)
1678 6 : regridCenterF = freq_from_vopt(regridCenter, regridVeloRestfrq);
1679 6 : regridCenterVel = regridCenter;
1680 : }
1681 : // Center was not specified
1682 : else
1683 : {
1684 2 : regridCenterF = (transNewXin[0] - transCHAN_WIDTH[0]
1685 2 : + transNewXin[oldNUM_CHAN - 1] + transCHAN_WIDTH[oldNUM_CHAN - 1]) / 2.;
1686 2 : regridCenterVel = vopt(regridCenterF, regridVeloRestfrq);
1687 2 : centerIsStart = false;
1688 : }
1689 :
1690 8 : if (nchan > 0)
1691 : {
1692 : lDouble cw;
1693 6 : lDouble divbytwo = 0.5;
1694 6 : if (centerIsStart)
1695 : {
1696 6 : divbytwo = 1.;
1697 : }
1698 6 : if (regridChanWidth > 0.)
1699 : {
1700 6 : cw = regridChanWidth;
1701 : }
1702 : // Determine channel width from first channel
1703 : else
1704 : {
1705 0 : lDouble upEdge = vopt(transNewXin[0] - transCHAN_WIDTH[0],regridVeloRestfrq);
1706 0 : lDouble loEdge = vopt(transNewXin[0] + transCHAN_WIDTH[0],regridVeloRestfrq);
1707 0 : cw = abs(upEdge - loEdge);
1708 : }
1709 6 : lDouble bwUpperEndF = 0.;
1710 :
1711 : // Start is end in velocity
1712 6 : if (centerIsStart && !startIsEnd)
1713 : {
1714 1 : bwUpperEndF = freq_from_vopt(regridCenterVel - (lDouble) nchan * cw * divbytwo,regridVeloRestfrq);
1715 : }
1716 : else
1717 : {
1718 5 : bwUpperEndF = freq_from_vopt(regridCenterVel + (lDouble) nchan * cw * divbytwo,regridVeloRestfrq);
1719 : }
1720 :
1721 6 : regridBandwidthF = abs(bwUpperEndF - regridCenterF) / divbytwo;
1722 :
1723 : // Can convert start to center
1724 6 : if (centerIsStart)
1725 : {
1726 6 : if (startIsEnd)
1727 : {
1728 5 : regridCenterVel = regridCenterVel + (lDouble) nchan * cw / 2.;
1729 : }
1730 : else
1731 : {
1732 1 : regridCenterVel = regridCenterVel - (lDouble) nchan * cw / 2.;
1733 : }
1734 :
1735 6 : regridCenterF = freq_from_vopt(regridCenterVel,regridVeloRestfrq);
1736 6 : centerIsStart = false;
1737 : }
1738 6 : nchan = 0; // indicate that nchan should not be used in the following
1739 : }
1740 2 : else if (regridBandwidth > 0.)
1741 : {
1742 : // can convert start to center
1743 0 : if (centerIsStart)
1744 : {
1745 0 : if (startIsEnd)
1746 : {
1747 0 : regridCenterVel = regridCenter + regridBandwidth / 2.;
1748 : }
1749 : else
1750 : {
1751 0 : regridCenterVel = regridCenter - regridBandwidth / 2.;
1752 : }
1753 0 : regridCenterF = freq_from_vopt(regridCenterVel, regridVeloRestfrq);
1754 0 : centerIsStart = false;
1755 : }
1756 :
1757 0 : lDouble bwUpperEndF = freq_from_vopt(regridCenterVel - regridBandwidth / 2.,regridVeloRestfrq);
1758 0 : regridBandwidthF = 2. * (bwUpperEndF - regridCenterF);
1759 : }
1760 :
1761 8 : if (regridChanWidth > 0. && regridChanWidthF < 0.)
1762 : {
1763 7 : lDouble chanUpperEdgeF = freq_from_vopt(regridCenterVel - regridChanWidth / 2.,regridVeloRestfrq);
1764 7 : regridChanWidthF = 2. * (chanUpperEdgeF - freq_from_vopt(regridCenterVel, regridVeloRestfrq));
1765 : }
1766 : }
1767 756 : else if (regridQuant == "freq")
1768 : {
1769 : // width parameter overrides regridChanWidth
1770 756 : if (width > 0)
1771 : {
1772 683 : regridChanWidth = width * transCHAN_WIDTH[0];
1773 : }
1774 :
1775 756 : if (start >= 0)
1776 : {
1777 683 : Int firstChan = start;
1778 683 : if (start >= (Int) transNewXin.size())
1779 : {
1780 1 : oss << " *** Parameter start exceeds total number of channels which is "
1781 1 : << transNewXin.size() << ". Set to 0." << endl;
1782 1 : firstChan = 0;
1783 1 : startIsEnd = false;
1784 : }
1785 :
1786 683 : if (startIsEnd)
1787 : {
1788 24 : regridCenter = transNewXin[firstChan] + transCHAN_WIDTH[firstChan] / 2.;
1789 : }
1790 : else
1791 : {
1792 659 : regridCenter = transNewXin[firstChan] - transCHAN_WIDTH[firstChan] / 2.;
1793 : }
1794 683 : centerIsStart = true;
1795 : }
1796 : else
1797 : {
1798 : // start is the center of the first channel
1799 73 : if (centerIsStart)
1800 : {
1801 : Double tcWidth;
1802 73 : if (regridChanWidth > 0.)
1803 : {
1804 59 : tcWidth = regridChanWidth;
1805 : }
1806 : else
1807 : {
1808 14 : tcWidth = transCHAN_WIDTH[0];
1809 : }
1810 :
1811 73 : if (startIsEnd)
1812 : {
1813 8 : regridCenter += tcWidth / 2.;
1814 : }
1815 : else
1816 : {
1817 65 : regridCenter -= tcWidth / 2.;
1818 : }
1819 : }
1820 : }
1821 756 : regridCenterF = regridCenter;
1822 756 : regridBandwidthF = regridBandwidth;
1823 756 : regridChanWidthF = regridChanWidth;
1824 : }
1825 0 : else if (regridQuant == "wave") {
1826 : // wavelength ...
1827 : lDouble regridCenterWav;
1828 0 : if (regridCenter > 0.)
1829 : {
1830 0 : if (centerIsStart)
1831 : {
1832 : Double tcWidth;
1833 0 : if (regridChanWidth > 0.)
1834 : {
1835 0 : tcWidth = regridChanWidth;
1836 : }
1837 : else
1838 : {
1839 0 : tcWidth = lambda(transNewXin[0] - transCHAN_WIDTH[0] / 2.) -
1840 0 : lambda(transNewXin[0] + transCHAN_WIDTH[0]/ 2.);
1841 : }
1842 :
1843 : // start is the center of the last channel (in freq)
1844 0 : if (startIsEnd)
1845 : {
1846 0 : regridCenter -= tcWidth / 2.;
1847 : }
1848 : // start is the center of the first channel (in freq)
1849 : else
1850 : {
1851 0 : regridCenter += tcWidth / 2.;
1852 : }
1853 : }
1854 0 : regridCenterF = freq_from_lambda(regridCenter);
1855 0 : regridCenterWav = regridCenter;
1856 : }
1857 : // center was not specified
1858 : else
1859 : {
1860 0 : regridCenterF = (transNewXin[0] + transNewXin[oldNUM_CHAN - 1])/ 2.;
1861 0 : regridCenterWav = lambda(regridCenterF);
1862 0 : centerIsStart = false;
1863 : }
1864 0 : if (nchan > 0)
1865 : {
1866 : lDouble cw;
1867 0 : lDouble divbytwo = 0.5;
1868 0 : if (centerIsStart)
1869 : {
1870 0 : divbytwo = 1.;
1871 : }
1872 :
1873 0 : if (regridChanWidth > 0.)
1874 : {
1875 0 : cw = regridChanWidth;
1876 : }
1877 : // Determine channel width from first channel
1878 : else
1879 : {
1880 0 : lDouble upEdge = lambda(transNewXin[0] - transCHAN_WIDTH[0]);
1881 0 : lDouble loEdge = lambda(transNewXin[0] + transCHAN_WIDTH[0]);
1882 0 : cw = abs(upEdge - loEdge);
1883 : }
1884 :
1885 0 : lDouble bwUpperEndF = 0.;
1886 0 : if (centerIsStart && !startIsEnd)
1887 : {
1888 0 : bwUpperEndF = freq_from_lambda(regridCenterWav - (lDouble) nchan * cw * divbytwo);
1889 : }
1890 : else
1891 : {
1892 0 : bwUpperEndF = freq_from_lambda(regridCenterWav + (lDouble) nchan * cw * divbytwo);
1893 : }
1894 :
1895 0 : regridBandwidthF = (bwUpperEndF - regridCenterF) / divbytwo;
1896 :
1897 : // Can convert start to center
1898 0 : if (centerIsStart)
1899 : {
1900 0 : if (startIsEnd)
1901 : {
1902 0 : regridCenterWav = regridCenterWav + (lDouble) nchan* cw / 2.;
1903 : }
1904 : else
1905 : {
1906 0 : regridCenterWav = regridCenterWav - (lDouble) nchan* cw / 2.;
1907 : }
1908 0 : regridCenterF = freq_from_lambda(regridCenterWav);
1909 0 : centerIsStart = false;
1910 : }
1911 0 : nchan = 0; // indicate that nchan should not be used in the following
1912 :
1913 : }
1914 0 : else if (regridBandwidth > 0. && regridBandwidth / 2.< regridCenterWav)
1915 : {
1916 : // Can convert start to center
1917 0 : if (centerIsStart)
1918 : {
1919 0 : if (startIsEnd)
1920 : {
1921 0 : regridCenterWav = regridCenter + regridBandwidth / 2.;
1922 : }
1923 : else
1924 : {
1925 0 : regridCenterWav = regridCenter - regridBandwidth / 2.;
1926 : }
1927 0 : regridCenterF = freq_from_lambda(regridCenterWav);
1928 0 : centerIsStart = false;
1929 : }
1930 0 : lDouble bwUpperEndF = lambda(regridCenterWav - regridBandwidth / 2.);
1931 0 : regridBandwidthF = 2. * (bwUpperEndF - regridCenterF);
1932 : }
1933 :
1934 0 : if (regridChanWidth > 0. && regridChanWidth / 2. < regridCenterWav)
1935 : {
1936 0 : lDouble chanUpperEdgeF = lambda(regridCenterWav - regridChanWidth / 2.);
1937 0 : regridChanWidthF = 2. * (chanUpperEdgeF - regridCenterF);
1938 : }
1939 : }
1940 : else
1941 : {
1942 0 : oss << "Invalid value " << regridQuant << " for parameter \"mode\".";
1943 0 : message = oss.str();
1944 0 : return false;
1945 : }
1946 : // (transformation of regrid parameters to frequencies completed)
1947 :
1948 : // Then determine the actually possible parameters
1949 : lDouble theRegridCenterF;
1950 : lDouble theRegridBWF;
1951 : lDouble theCentralChanWidthF;
1952 :
1953 : // For vrad and vopt also need to keep this adjusted value
1954 807 : lDouble theChanWidthX = -1.;
1955 :
1956 807 : if (regridCenterF < 0.) // means "not set"
1957 : {
1958 : // Keep regrid center as it is in the data
1959 20 : theRegridCenterF = (transNewXin[0] - transCHAN_WIDTH[0] / 2.
1960 20 : + transNewXin[oldNUM_CHAN - 1] + transCHAN_WIDTH[oldNUM_CHAN - 1] / 2.) / 2.;
1961 20 : centerIsStart = false;
1962 : }
1963 : // regridCenterF was set
1964 : else
1965 : {
1966 : // Keep center in limits
1967 787 : theRegridCenterF = regridCenterF;
1968 787 : if ((theRegridCenterF - (transNewXin[oldNUM_CHAN - 1] + transCHAN_WIDTH[oldNUM_CHAN - 1] / 2.)) > 1.) // 1 Hz tolerance
1969 : {
1970 1 : oss << "*** Requested center of SPW " << theRegridCenterF
1971 1 : << " Hz is too large by "
1972 1 : << theRegridCenterF - transNewXin[oldNUM_CHAN - 1] + transCHAN_WIDTH[oldNUM_CHAN - 1] / 2.
1973 1 : << " Hz\n";
1974 1 : theRegridCenterF = transNewXin[oldNUM_CHAN - 1] + transCHAN_WIDTH[oldNUM_CHAN - 1] / 2.;
1975 1 : oss << "*** Reset to maximum possible value " << theRegridCenterF << " Hz";
1976 : }
1977 786 : else if (theRegridCenterF < (transNewXin[0] - transCHAN_WIDTH[0] / 2.))
1978 : {
1979 18 : Double diff = (transNewXin[0] - transCHAN_WIDTH[0] / 2.) - theRegridCenterF;
1980 :
1981 : // Cope with numerical accuracy problems
1982 18 : if (diff > 1.)
1983 : {
1984 17 : oss << "*** Requested center of SPW (" << theRegridCenterF
1985 17 : << " Hz) is smaller than minimum possible value";
1986 17 : oss << " by " << diff << " Hz";
1987 : }
1988 :
1989 18 : theRegridCenterF = transNewXin[0] - transCHAN_WIDTH[0] / 2.;
1990 18 : if (diff > 1.)
1991 : {
1992 17 : oss << "\n*** Reset to minimum possible value " << theRegridCenterF << " Hz";
1993 : }
1994 : }
1995 : }
1996 :
1997 807 : if (regridBandwidthF <= 0. || nchan != 0) // "not set" or use nchan instead
1998 : {
1999 : // Keep bandwidth as is
2000 801 : theRegridBWF = transNewXin[oldNUM_CHAN - 1] - transNewXin[0]
2001 801 : + transCHAN_WIDTH[0] / 2. + transCHAN_WIDTH[oldNUM_CHAN - 1] / 2.;
2002 :
2003 : // Use nchan parameter if available
2004 801 : if (nchan != 0)
2005 : {
2006 801 : if (nchan < 0)
2007 : {
2008 551 : if (regridQuant == "freq" || regridQuant == "vrad") // i.e. equidistant in freq
2009 : {
2010 : // Define via width of first channel to avoid numerical problems
2011 :
2012 : // channel width not set
2013 549 : if (regridChanWidthF <= 0.)
2014 : {
2015 4 : theRegridBWF = transCHAN_WIDTH[0] *
2016 2 : floor((theRegridBWF + transCHAN_WIDTH[0] * 0.01)/ transCHAN_WIDTH[0]);
2017 : }
2018 : else
2019 : {
2020 547 : theRegridBWF = regridChanWidthF *
2021 547 : floor((theRegridBWF + regridChanWidthF * 0.01)/ regridChanWidthF);
2022 : }
2023 : }
2024 : }
2025 : // Channel width not set
2026 250 : else if (regridChanWidthF <= 0.)
2027 : {
2028 13 : theRegridBWF = transCHAN_WIDTH[0] * nchan;
2029 : }
2030 : else
2031 : {
2032 237 : theRegridBWF = regridChanWidthF * nchan;
2033 : }
2034 :
2035 : // Center was not set by user but calculated
2036 801 : if (regridCenterF <= 0. || regridCenter < -C::c)
2037 : {
2038 : // Need to update
2039 39 : theRegridCenterF = transNewXin[0] - transCHAN_WIDTH[0] / 2. + theRegridBWF / 2.;
2040 39 : centerIsStart = false;
2041 : }
2042 : // Center but not nchan was set by user
2043 762 : else if (nchan < 0)
2044 : {
2045 : // Verify that the bandwidth is correct
2046 540 : if (centerIsStart)
2047 : {
2048 540 : if (startIsEnd)
2049 : {
2050 19 : theRegridBWF = theRegridCenterF - transNewXin[0] + transCHAN_WIDTH[0] / 2.;
2051 : }
2052 : // start is start
2053 : else
2054 : {
2055 521 : theRegridBWF = transNewXin[oldNUM_CHAN - 1] +
2056 521 : transCHAN_WIDTH[oldNUM_CHAN - 1] / 2. -
2057 : theRegridCenterF;
2058 : }
2059 540 : if (regridQuant == "freq" || regridQuant == "vrad") // i.e. equidistant in freq
2060 : {
2061 : // Define via width of first channel to avoid numerical problems
2062 540 : if (regridChanWidthF <= 0.) { // channel width not set
2063 2 : theRegridBWF = transCHAN_WIDTH[0]
2064 1 : * floor((theRegridBWF + transCHAN_WIDTH[0]* 0.01) / transCHAN_WIDTH[0]);
2065 : }
2066 : else
2067 : {
2068 539 : theRegridBWF = regridChanWidthF
2069 539 : * floor((theRegridBWF+ regridChanWidthF* 0.01)/ regridChanWidthF);
2070 : }
2071 : }
2072 : }
2073 : // center is center
2074 : else {
2075 0 : theRegridBWF = 2. * min((Double) (theRegridCenterF - transNewXin[0]- transCHAN_WIDTH[0]),
2076 0 : (Double) (transNewXin[oldNUM_CHAN - 1] + transCHAN_WIDTH[oldNUM_CHAN - 1] - theRegridCenterF));
2077 : }
2078 : }
2079 : }
2080 :
2081 : // Now can convert start to center
2082 1537 : if (centerIsStart)
2083 : {
2084 736 : if (startIsEnd)
2085 : {
2086 31 : theRegridCenterF = theRegridCenterF - theRegridBWF / 2.;
2087 : }
2088 : else
2089 : {
2090 705 : theRegridCenterF = theRegridCenterF + theRegridBWF / 2.;
2091 : }
2092 736 : centerIsStart = false;
2093 : }
2094 : }
2095 : // regridBandwidthF was set
2096 : else {
2097 : // Determine actually possible bandwidth
2098 : // width will be truncated to the maximum width possible
2099 : // symmetrically around the value given by "regrid_center"
2100 6 : theRegridBWF = regridBandwidthF;
2101 :
2102 : // Now can convert start to center
2103 6 : if (centerIsStart)
2104 : {
2105 0 : if (startIsEnd)
2106 : {
2107 0 : theRegridCenterF = theRegridCenterF - theRegridBWF / 2.;
2108 : }
2109 : else
2110 : {
2111 0 : theRegridCenterF = theRegridCenterF + theRegridBWF / 2.;
2112 : }
2113 0 : centerIsStart = false;
2114 : }
2115 :
2116 6 : Double rangeTol = 1.; // Hz
2117 6 : if ((regridQuant == "vopt" || regridQuant == "wave")) // i.e. if the center is the center w.r.t. wavelength
2118 : {
2119 6 : rangeTol = transCHAN_WIDTH[0];
2120 : }
2121 :
2122 6 : if ((theRegridCenterF + theRegridBWF / 2.) - (transNewXin[oldNUM_CHAN - 1] + transCHAN_WIDTH[oldNUM_CHAN - 1] / 2.) > rangeTol)
2123 : {
2124 : oss << " *** Input spectral window exceeds upper end of original window. "
2125 0 : "Adjusting to max. possible value." << endl;
2126 0 : theRegridBWF = min( (Double) fabs(transNewXin[oldNUM_CHAN - 1] + transCHAN_WIDTH[oldNUM_CHAN - 1] / 2.- theRegridCenterF),
2127 0 : (Double) fabs(theRegridCenterF - transNewXin[0]+ transCHAN_WIDTH[0] / 2.)) * 2.;
2128 :
2129 0 : if (theRegridBWF < transCHAN_WIDTH[0])
2130 : {
2131 0 : theRegridCenterF = ( transNewXin[0]
2132 0 : + transCHAN_WIDTH[oldNUM_CHAN - 1]
2133 0 : + transCHAN_WIDTH[oldNUM_CHAN - 1] / 2.
2134 0 : - transCHAN_WIDTH[0] / 2.) / 2.;
2135 0 : theRegridBWF = transCHAN_WIDTH[oldNUM_CHAN - 1]
2136 0 : - transNewXin[0] + transCHAN_WIDTH[oldNUM_CHAN - 1] / 2. + transCHAN_WIDTH[0] / 2.;
2137 : }
2138 : }
2139 6 : if ((theRegridCenterF - theRegridBWF / 2.) - (transNewXin[0] - transCHAN_WIDTH[0] / 2.) < -rangeTol)
2140 : {
2141 : oss << " *** Input spectral window exceeds lower end of original window. "
2142 2 : " Adjusting to max. possible value."<< endl;
2143 :
2144 2 : theRegridBWF = min( (Double) fabs(transNewXin[oldNUM_CHAN - 1] + transCHAN_WIDTH[oldNUM_CHAN - 1] / 2. - theRegridCenterF),
2145 2 : (Double) fabs(theRegridCenterF - transNewXin[0] + transCHAN_WIDTH[0] / 2.)) * 2.;
2146 :
2147 2 : if (theRegridBWF < transCHAN_WIDTH[0])
2148 : {
2149 0 : theRegridCenterF = (transNewXin[0]
2150 0 : + transCHAN_WIDTH[oldNUM_CHAN - 1]
2151 0 : + transCHAN_WIDTH[oldNUM_CHAN - 1] / 2.
2152 0 : - transCHAN_WIDTH[0] / 2.) / 2.;
2153 0 : theRegridBWF = transCHAN_WIDTH[oldNUM_CHAN - 1]
2154 0 : - transNewXin[0]
2155 0 : + transCHAN_WIDTH[oldNUM_CHAN - 1] / 2.
2156 0 : + transCHAN_WIDTH[0] / 2.;
2157 : }
2158 : }
2159 : }
2160 :
2161 807 : if (regridChanWidthF <= 0.) // "not set"
2162 : {
2163 16 : if (nchan != 0 || centerIsStartC) // use first channel
2164 : {
2165 16 : theCentralChanWidthF = transCHAN_WIDTH[0];
2166 : }
2167 : else
2168 : {
2169 : // keep channel width similar to the old one
2170 0 : theCentralChanWidthF = transCHAN_WIDTH[oldNUM_CHAN / 2]; // use channel width from
2171 : // near central channel
2172 : }
2173 : }
2174 : // regridChanWidthF was set
2175 : else
2176 : {
2177 : // Keep in limits
2178 791 : theCentralChanWidthF = regridChanWidthF;
2179 :
2180 : // Too large => make a single channel
2181 791 : if (theCentralChanWidthF > theRegridBWF)
2182 : {
2183 0 : theCentralChanWidthF = theRegridBWF;
2184 : oss
2185 0 : << " *** Requested new channel width exceeds defined SPW width."
2186 0 : << endl
2187 0 : << " Creating a single channel with the defined SPW width."
2188 0 : << endl;
2189 : }
2190 : // Check if too small
2191 791 : else if (theCentralChanWidthF < transCHAN_WIDTH[0])
2192 : {
2193 : // Determine smallest channel width
2194 8 : lDouble smallestChanWidth = 1E30;
2195 8 : Int ii = 0;
2196 6104 : for (Int i = 0; i < oldNUM_CHAN; i++)
2197 : {
2198 6096 : if (transCHAN_WIDTH[i] < smallestChanWidth)
2199 : {
2200 15 : smallestChanWidth = transCHAN_WIDTH[i];
2201 15 : ii = i;
2202 : }
2203 : }
2204 :
2205 : // 1 Hz tolerance to cope with numerical accuracy problems
2206 8 : if (theCentralChanWidthF < smallestChanWidth - 1.)
2207 : {
2208 2 : oss << " *** Requested new channel width (" << theCentralChanWidthF << " Hz) "
2209 2 : << "is smaller than smallest original channel width" << endl;
2210 2 : oss << " which is " << smallestChanWidth << " Hz" << endl;
2211 :
2212 2 : if (regridQuant == "vrad")
2213 : {
2214 1 : oss << " or "
2215 1 : << (vrad(transNewXin[ii],regridVeloRestfrq)
2216 1 : - vrad(transNewXin[ii] + transCHAN_WIDTH[ii] / 2.,regridVeloRestfrq)) * 2. << " m/s";
2217 : }
2218 :
2219 2 : if (regridQuant == "vopt")
2220 : {
2221 0 : oss << " or "
2222 0 : << (vopt(transNewXin[ii],regridVeloRestfrq)
2223 0 : - vopt(transNewXin[ii] + transCHAN_WIDTH[ii] / 2.,regridVeloRestfrq)) * 2. << " m/s";
2224 : }
2225 :
2226 2 : message = oss.str();
2227 2 : return false;
2228 :
2229 : }
2230 : // input channel width was OK, memorize
2231 : else
2232 : {
2233 6 : theChanWidthX = regridChanWidth;
2234 : }
2235 : }
2236 : }
2237 :
2238 805 : oss << " Channels equidistant in " << regridQuant << endl
2239 805 : << " Central frequency (in output frame) = " << theRegridCenterF << " Hz";
2240 :
2241 805 : if (regridQuant == "vrad")
2242 : {
2243 42 : oss << " == " << vrad(theRegridCenterF, regridVeloRestfrq) << " m/s radio velocity";
2244 : }
2245 763 : else if (regridQuant == "vopt")
2246 : {
2247 8 : oss << " == " << vopt(theRegridCenterF, regridVeloRestfrq) << " m/s optical velocity";
2248 : }
2249 755 : else if (regridQuant == "wave")
2250 : {
2251 0 : oss << " == " << lambda(theRegridCenterF) << " m wavelength";
2252 : }
2253 805 : oss << endl;
2254 :
2255 805 : if (isDescending)
2256 : {
2257 36 : oss << " Channel central frequency is decreasing with increasing channel number." << endl;
2258 : }
2259 :
2260 805 : oss << " Width of central channel (in output frame) = " << theCentralChanWidthF << " Hz";
2261 :
2262 805 : if (regridQuant == "vrad")
2263 : {
2264 42 : oss << " == " << vrad(theRegridCenterF - theCentralChanWidthF,regridVeloRestfrq)
2265 42 : - vrad(theRegridCenterF,regridVeloRestfrq) << " m/s radio velocity";
2266 : }
2267 763 : else if (regridQuant == "vopt")
2268 : {
2269 8 : oss << " == " << vopt(theRegridCenterF - theCentralChanWidthF,regridVeloRestfrq)
2270 8 : - vopt(theRegridCenterF,regridVeloRestfrq) << " m/s optical velocity";
2271 : }
2272 755 : else if (regridQuant == "wave")
2273 : {
2274 0 : oss << " == " << lambda(theRegridCenterF - theCentralChanWidthF)
2275 0 : - lambda(theRegridCenterF) << " m wavelength";
2276 : }
2277 805 : oss << endl;
2278 :
2279 : // Now calculate newChanLoBound, and newChanHiBound from theRegridCenterF, theRegridBWF, theCentralChanWidthF
2280 1610 : vector<lDouble> loFBup; // The lower bounds for the new channels starting from the central channel going up
2281 1610 : vector<lDouble> hiFBup; // The lower bounds for the new channels starting from the central channel going up
2282 1610 : vector<lDouble> loFBdown; // The lower bounds for the new channels starting from the central channel going down
2283 1610 : vector<lDouble> hiFBdown; // The lower bounds for the new channels starting from the central channel going down
2284 :
2285 805 : lDouble edgeTolerance = theCentralChanWidthF * 0.01; // Needed to avoid numerical accuracy problems
2286 :
2287 : // Re-gridding in radio velocity ...
2288 805 : if (regridQuant == "vrad")
2289 : {
2290 : // Create freq boundaries equidistant and contiguous in radio velocity
2291 42 : lDouble upperEndF = theRegridCenterF + theRegridBWF / 2.;
2292 42 : lDouble lowerEndF = theRegridCenterF - theRegridBWF / 2.;
2293 42 : lDouble upperEndV = vrad(upperEndF, regridVeloRestfrq);
2294 42 : lDouble lowerEndV = vrad(lowerEndF, regridVeloRestfrq);
2295 : lDouble velLo;
2296 : lDouble velHi;
2297 :
2298 : // Want to keep the center of the center channel at the center
2299 : // of the new center channel if the bandwidth is an odd multiple
2300 : // of the new channel width, otherwise the center channel is the
2301 : // lower edge of the new center channel
2302 42 : lDouble tnumChan = floor((theRegridBWF + edgeTolerance) / theCentralChanWidthF);
2303 :
2304 42 : if ((Int) tnumChan % 2 != 0)
2305 : {
2306 : // Odd multiple
2307 5 : loFBup.push_back(theRegridCenterF - theCentralChanWidthF / 2.);
2308 5 : hiFBup.push_back(theRegridCenterF + theCentralChanWidthF / 2.);
2309 5 : loFBdown.push_back(theRegridCenterF - theCentralChanWidthF / 2.);
2310 5 : hiFBdown.push_back(theRegridCenterF + theCentralChanWidthF / 2.);
2311 : }
2312 : else
2313 : {
2314 37 : loFBup.push_back(theRegridCenterF);
2315 37 : hiFBup.push_back(theRegridCenterF + theCentralChanWidthF);
2316 37 : loFBdown.push_back(theRegridCenterF);
2317 37 : hiFBdown.push_back(theRegridCenterF + theCentralChanWidthF);
2318 : }
2319 :
2320 : // Cannot use original channel width in velocity units
2321 42 : if (theChanWidthX < 0)
2322 : {
2323 : // Need to calculate back from central channel width in Hz
2324 36 : theChanWidthX = vrad(loFBup[0], regridVeloRestfrq) - vrad(hiFBup[0], regridVeloRestfrq);
2325 : }
2326 :
2327 : // calc velocity corresponding to the upper end (in freq) of the
2328 : // last added channel which is the lower end of the next channel
2329 42 : velLo = vrad(hiFBup[0], regridVeloRestfrq);
2330 :
2331 : // calc velocity corresponding to the upper end (in freq) of the next channel
2332 42 : velHi = velLo - theChanWidthX; // vrad goes down as freq goes up!
2333 :
2334 : // (Preventing accuracy problems)
2335 2422 : while (upperEndV - theChanWidthX / 10. < velHi)
2336 : {
2337 : // calc frequency of the upper end (in freq) of the next channel
2338 2380 : lDouble freqHi = freq_from_vrad(velHi, regridVeloRestfrq);
2339 :
2340 : // End of bandwidth not yet reached
2341 2380 : if (freqHi <= upperEndF + edgeTolerance)
2342 : {
2343 2380 : loFBup.push_back(hiFBup.back());
2344 2380 : hiFBup.push_back(freqHi);
2345 : }
2346 0 : else if (freqHi < upperEndF + edgeTolerance)
2347 : {
2348 0 : loFBup.push_back(hiFBup.back());
2349 0 : hiFBup.push_back(upperEndF);
2350 0 : break;
2351 : }
2352 : else
2353 : {
2354 0 : break;
2355 : }
2356 :
2357 : // calc velocity corresponding to the upper end (in freq) of the added channel
2358 2380 : velLo = vrad(hiFBup.back(), regridVeloRestfrq);
2359 :
2360 : // calc velocity corresponding to the upper end (in freq) of the next channel
2361 2380 : velHi = velLo - theChanWidthX; // vrad goes down as freq goes up
2362 : }
2363 :
2364 : // calc velocity corresponding to the lower end (in freq) of the
2365 : // Last added channel which is the upper end of the next channel
2366 42 : velHi = vrad(loFBdown[0], regridVeloRestfrq);
2367 :
2368 : // calc velocity corresponding to the lower end (in freq) of the next channel
2369 42 : velLo = velHi + theChanWidthX; // vrad goes up as freq goes down!
2370 :
2371 : // (Preventing accuracy problems)
2372 2459 : while (velLo < lowerEndV + theChanWidthX / 10.)
2373 : {
2374 : // calc frequency of the lower end (in freq) of the next channel
2375 2417 : lDouble freqLo = freq_from_vrad(velLo, regridVeloRestfrq);
2376 :
2377 : // End of bandwidth not yet reached
2378 2417 : if (freqLo >= lowerEndF - edgeTolerance)
2379 : {
2380 2417 : hiFBdown.push_back(loFBdown.back());
2381 2417 : loFBdown.push_back(freqLo);
2382 : }
2383 0 : else if (freqLo > lowerEndF - edgeTolerance)
2384 : {
2385 0 : hiFBdown.push_back(loFBdown.back());
2386 0 : loFBdown.push_back(lowerEndF);
2387 0 : break;
2388 : }
2389 : else
2390 : {
2391 0 : break;
2392 : }
2393 :
2394 : // calc velocity corresponding to the upper end of the next channel
2395 2417 : velHi = vrad(loFBdown.back(), regridVeloRestfrq);
2396 :
2397 : // calc velocity corresponding to the lower end (in freq) of the next channel
2398 2417 : velLo = velHi + theChanWidthX; // vrad goes up as freq goes down
2399 : }
2400 : }
2401 : // Regridding in optical velocity ...
2402 763 : else if (regridQuant == "vopt")
2403 : {
2404 : // Create freq boundaries equidistant and contiguous in optical velocity
2405 8 : lDouble upperEndF = theRegridCenterF + theRegridBWF / 2.;
2406 8 : lDouble lowerEndF = theRegridCenterF - theRegridBWF / 2.;
2407 8 : lDouble upperEndV = vopt(upperEndF, regridVeloRestfrq);
2408 8 : lDouble lowerEndV = vopt(lowerEndF, regridVeloRestfrq);
2409 : lDouble velLo;
2410 : lDouble velHi;
2411 :
2412 : // Want to keep the center of the center channel at the center
2413 : // of the new center channel if the bandwidth is an odd multiple
2414 : // of the new channel width, otherwise the center channel is the
2415 : // lower edge of the new center channel
2416 :
2417 : // Enlarged edge tolerance since channels non-equidistant in freq
2418 8 : lDouble tnumChan = floor((theRegridBWF + edgeTolerance) / theCentralChanWidthF);
2419 :
2420 : // Odd multiple
2421 8 : if ((Int) tnumChan % 2 != 0)
2422 : {
2423 :
2424 4 : loFBup.push_back(theRegridCenterF - theCentralChanWidthF / 2.);
2425 4 : hiFBup.push_back(theRegridCenterF + theCentralChanWidthF / 2.);
2426 4 : loFBdown.push_back(theRegridCenterF - theCentralChanWidthF / 2.);
2427 4 : hiFBdown.push_back(theRegridCenterF + theCentralChanWidthF / 2.);
2428 : }
2429 : else
2430 : {
2431 4 : loFBup.push_back(theRegridCenterF);
2432 4 : hiFBup.push_back(theRegridCenterF + theCentralChanWidthF);
2433 4 : loFBdown.push_back(theRegridCenterF);
2434 4 : hiFBdown.push_back(theRegridCenterF + theCentralChanWidthF);
2435 : }
2436 :
2437 : // Cannot use original channel width in velocity units
2438 8 : if (theChanWidthX < 0)
2439 : {
2440 : // Need to calculate back from central channel width in Hz
2441 8 : theChanWidthX = vopt(loFBup[0], regridVeloRestfrq) - vopt(hiFBup[0], regridVeloRestfrq);
2442 : }
2443 :
2444 : // calc velocity corresponding to the upper end (in freq) of the
2445 : // last added channel which is the lower end of the next channel
2446 8 : velLo = vopt(hiFBup[0], regridVeloRestfrq);
2447 :
2448 : // calc velocity corresponding to the upper end (in freq) of the next channel
2449 8 : velHi = velLo - theChanWidthX; // vopt goes down as freq goes up!
2450 :
2451 : // (Preventing accuracy problems)
2452 108 : while (upperEndV - velHi < theChanWidthX / 10.)
2453 : {
2454 : // calc frequency of the upper end (in freq) of the next channel
2455 101 : lDouble freqHi = freq_from_vopt(velHi, regridVeloRestfrq);
2456 :
2457 : // End of bandwidth not yet reached
2458 101 : if (freqHi <= upperEndF + edgeTolerance)
2459 : {
2460 100 : loFBup.push_back(hiFBup.back());
2461 100 : hiFBup.push_back(freqHi);
2462 : }
2463 1 : else if (freqHi < upperEndF + edgeTolerance)
2464 : {
2465 0 : loFBup.push_back(hiFBup.back());
2466 0 : hiFBup.push_back(upperEndF);
2467 1 : break;
2468 : }
2469 : else
2470 : {
2471 1 : break;
2472 : }
2473 :
2474 : // calc velocity corresponding to the upper end (in freq) of the added channel
2475 100 : velLo = vopt(hiFBup.back(), regridVeloRestfrq);
2476 : // calc velocity corresponding to the upper end (in freq) of the next channel
2477 100 : velHi = velLo - theChanWidthX; // vopt goes down as freq goes up
2478 : }
2479 :
2480 : // calc velocity corresponding to the lower end (in freq) of the
2481 : // last added channel which is the upper end of the next channel
2482 8 : velHi = vopt(loFBdown[0], regridVeloRestfrq);
2483 :
2484 : // calc velocity corresponding to the lower end (in freq) of the next channel
2485 8 : velLo = velHi + theChanWidthX; // vopt goes up as freq goes down!
2486 :
2487 : // (Preventing accuracy problems)
2488 113 : while (velLo - lowerEndV < theChanWidthX / 10.)
2489 : {
2490 : // calc frequency of the lower end (in freq) of the next channel
2491 105 : lDouble freqLo = freq_from_vopt(velLo, regridVeloRestfrq);
2492 :
2493 : // End of bandwidth not yet reached
2494 105 : if (freqLo >= lowerEndF - edgeTolerance)
2495 : {
2496 105 : hiFBdown.push_back(loFBdown.back());
2497 105 : loFBdown.push_back(freqLo);
2498 : }
2499 0 : else if (freqLo > lowerEndF - edgeTolerance)
2500 : {
2501 0 : hiFBdown.push_back(loFBdown.back());
2502 0 : loFBdown.push_back(lowerEndF);
2503 0 : break;
2504 : }
2505 : else
2506 : {
2507 0 : break;
2508 : }
2509 :
2510 : // calc velocity corresponding to the upper end of the next channel
2511 105 : velHi = vopt(loFBdown.back(), regridVeloRestfrq);
2512 : // calc velocity corresponding to the lower end (in freq) of the next channel
2513 105 : velLo = velHi + theChanWidthX; // vopt goes up as freq goes down
2514 : }
2515 : }
2516 : // Re-gridding in frequency ...
2517 755 : else if (regridQuant == "freq")
2518 : {
2519 : // Create freq boundaries equidistant and contiguous in frequency
2520 755 : lDouble upperEndF = theRegridCenterF + theRegridBWF / 2.;
2521 755 : lDouble lowerEndF = theRegridCenterF - theRegridBWF / 2.;
2522 :
2523 : // Want to keep the center of the center channel at the center
2524 : // of the new center channel if the bandwidth is an odd multiple
2525 : // of the new channel width, otherwise the center channel is the
2526 : // lower edge of the new center channel
2527 755 : lDouble tnumChan = floor((theRegridBWF + edgeTolerance) / theCentralChanWidthF);
2528 :
2529 : // Odd multiple
2530 755 : if ((Int) tnumChan % 2 != 0)
2531 : {
2532 285 : loFBup.push_back(theRegridCenterF - theCentralChanWidthF / 2.);
2533 285 : hiFBup.push_back(theRegridCenterF + theCentralChanWidthF / 2.);
2534 285 : loFBdown.push_back(theRegridCenterF - theCentralChanWidthF / 2.);
2535 285 : hiFBdown.push_back(theRegridCenterF + theCentralChanWidthF / 2.);
2536 : }
2537 : else
2538 : {
2539 470 : loFBup.push_back(theRegridCenterF);
2540 470 : hiFBup.push_back(theRegridCenterF + theCentralChanWidthF);
2541 470 : loFBdown.push_back(theRegridCenterF);
2542 470 : hiFBdown.push_back(theRegridCenterF + theCentralChanWidthF);
2543 : }
2544 :
2545 84864 : while (hiFBup.back() < upperEndF + edgeTolerance)
2546 : {
2547 : // calc frequency of the upper end of the next channel
2548 84864 : lDouble freqHi = hiFBup.back() + theCentralChanWidthF;
2549 :
2550 : // End of bandwidth not yet reached
2551 84864 : if (freqHi <= upperEndF + edgeTolerance)
2552 : {
2553 84109 : loFBup.push_back(hiFBup.back());
2554 84109 : hiFBup.push_back(freqHi);
2555 : }
2556 : else
2557 : {
2558 755 : break;
2559 : }
2560 : }
2561 :
2562 85334 : while (loFBdown.back() > lowerEndF - edgeTolerance)
2563 : {
2564 : // calc frequency of the lower end of the next channel
2565 85334 : lDouble freqLo = loFBdown.back() - theCentralChanWidthF;
2566 :
2567 : // End of bandwidth not yet reached
2568 85334 : if (freqLo >= lowerEndF - edgeTolerance)
2569 : {
2570 84579 : hiFBdown.push_back(loFBdown.back());
2571 84579 : loFBdown.push_back(freqLo);
2572 : }
2573 : else
2574 : {
2575 755 : break;
2576 : }
2577 : }
2578 : }
2579 : // Re-gridding in wavelength ...
2580 0 : else if (regridQuant == "wave")
2581 : {
2582 : // Create freq boundaries equidistant and contiguous in wavelength
2583 0 : lDouble upperEndF = theRegridCenterF + theRegridBWF / 2.;
2584 0 : lDouble lowerEndF = theRegridCenterF - theRegridBWF / 2.;
2585 0 : lDouble upperEndL = lambda(upperEndF);
2586 0 : lDouble lowerEndL = lambda(lowerEndF);
2587 : lDouble lambdaLo;
2588 : lDouble lambdaHi;
2589 :
2590 : // Want to keep the center of the center channel at the center
2591 : // of the new center channel if the bandwidth is an odd multiple
2592 : // of the new channel width, otherwise the center channel is the
2593 : // lower edge of the new center channel
2594 0 : lDouble tnumChan = floor((theRegridBWF + edgeTolerance) / theCentralChanWidthF);
2595 :
2596 : // Odd multiple
2597 0 : if ((Int) tnumChan % 2 != 0)
2598 : {
2599 0 : loFBup.push_back(theRegridCenterF - theCentralChanWidthF / 2.);
2600 0 : hiFBup.push_back(theRegridCenterF + theCentralChanWidthF / 2.);
2601 0 : loFBdown.push_back(theRegridCenterF - theCentralChanWidthF / 2.);
2602 0 : hiFBdown.push_back(theRegridCenterF + theCentralChanWidthF / 2.);
2603 : }
2604 : else
2605 : {
2606 0 : loFBup.push_back(theRegridCenterF);
2607 0 : hiFBup.push_back(theRegridCenterF + theCentralChanWidthF);
2608 0 : loFBdown.push_back(theRegridCenterF);
2609 0 : hiFBdown.push_back(theRegridCenterF + theCentralChanWidthF);
2610 : }
2611 :
2612 : // Cannot use original channel width in wavelength units
2613 0 : if (theChanWidthX < 0)
2614 : {
2615 : // Need to calculate back from central channel width in Hz
2616 0 : theChanWidthX = lambda(loFBup[0]) - lambda(hiFBup[0]);
2617 : }
2618 :
2619 : // calc wavelength corresponding to the upper end (in freq) of the
2620 : // last added channel which is the lower end of the next channel
2621 0 : lambdaLo = lambda(hiFBup[0]);
2622 :
2623 : // calc wavelength corresponding to the upper end (in freq) of the next channel
2624 0 : lambdaHi = lambdaLo - theChanWidthX; // lambda goes down as freq goes up!
2625 :
2626 : // (Preventing accuracy problems)
2627 0 : while (upperEndL - lambdaHi < theChanWidthX / 10.)
2628 : {
2629 : // calc frequency of the upper end (in freq) of the next channel
2630 0 : lDouble freqHi = freq_from_lambda(lambdaHi);
2631 :
2632 : // End of bandwidth not yet reached
2633 0 : if (freqHi <= upperEndF + edgeTolerance)
2634 : {
2635 0 : loFBup.push_back(hiFBup.back());
2636 0 : hiFBup.push_back(freqHi);
2637 : }
2638 0 : else if (freqHi < upperEndF + edgeTolerance)
2639 : {
2640 0 : loFBup.push_back(hiFBup.back());
2641 0 : hiFBup.push_back(upperEndF);
2642 0 : break;
2643 : }
2644 : else
2645 : {
2646 0 : break;
2647 : }
2648 :
2649 : // calc wavelength corresponding to the upper end (in freq) of the added channel
2650 0 : lambdaLo = lambda(hiFBup.back());
2651 : // calc wavelength corresponding to the upper end (in freq) of the next channel
2652 0 : lambdaHi = lambdaLo - theChanWidthX; // lambda goes down as freq goes up
2653 : }
2654 :
2655 : // calc wavelength corresponding to the lower end (in freq) of the
2656 : // last added channel which is the upper end of the next channel
2657 0 : lambdaHi = lambda(loFBdown[0]);
2658 :
2659 : // calc wavelength corresponding to the lower end (in freq) of the next channel
2660 0 : lambdaLo = lambdaHi + theChanWidthX; // lambda goes up as freq goes down!
2661 :
2662 :
2663 : // (Preventing accuracy problems)
2664 0 : while (lambdaLo - lowerEndL < theChanWidthX / 10.)
2665 : {
2666 : // calc frequency of the lower end (in freq) of the next channel
2667 0 : lDouble freqLo = freq_from_lambda(lambdaLo);
2668 :
2669 : // End of bandwidth not yet reached
2670 0 : if (freqLo >= lowerEndF - edgeTolerance)
2671 : {
2672 0 : hiFBdown.push_back(loFBdown.back());
2673 0 : loFBdown.push_back(freqLo);
2674 : }
2675 0 : else if (freqLo > lowerEndF - edgeTolerance)
2676 : {
2677 0 : hiFBdown.push_back(loFBdown.back());
2678 0 : loFBdown.push_back(lowerEndF);
2679 0 : break;
2680 : }
2681 : else
2682 : {
2683 0 : break;
2684 : }
2685 :
2686 : // calc wavelength corresponding to the upper end of the next channel
2687 0 : lambdaHi = lambda(loFBdown.back());
2688 : // calc wavelength corresponding to the lower end (in freq) of the next channel
2689 0 : lambdaLo = lambdaHi + theChanWidthX; // wavelength goes up as freq goes down
2690 : }
2691 :
2692 : }
2693 : // should not get here
2694 : else
2695 : {
2696 0 : oss << "Invalid value " << regridQuant << " for parameter \"mode\".";
2697 0 : message = oss.str();
2698 0 : return false;
2699 : }
2700 :
2701 805 : Int numNewChanDown = loFBdown.size();
2702 805 : Int numNewChanUp = loFBup.size();
2703 :
2704 : // central channel contained in both vectors
2705 805 : newChanLoBound.resize(numNewChanDown + numNewChanUp - 1);
2706 :
2707 805 : newChanHiBound.resize(numNewChanDown + numNewChanUp - 1);
2708 88711 : for (Int i = 0; i < numNewChanDown; i++)
2709 : {
2710 87906 : Int k = numNewChanDown - i - 1; // Need to assign in reverse
2711 87906 : newChanLoBound[i] = loFBdown[k];
2712 87906 : newChanHiBound[i] = hiFBdown[k];
2713 : }
2714 87394 : for (Int i = 1; i < numNewChanUp; i++) // Start at 1 to omit the central channel here
2715 : {
2716 86589 : newChanLoBound[i + numNewChanDown - 1] = loFBup[i];
2717 86589 : newChanHiBound[i + numNewChanDown - 1] = hiFBup[i];
2718 : }
2719 :
2720 805 : uInt nc = newChanLoBound.size();
2721 805 : oss << " Number of channels = " << nc << endl;
2722 805 : oss << " Total width of SPW (in output frame) = " << newChanHiBound[nc - 1] - newChanLoBound[0] << " Hz" << endl;
2723 805 : oss << " Lower edge = " << newChanLoBound[0] << " Hz,"
2724 805 : << " upper edge = " << newChanHiBound[nc - 1] << " Hz" << endl;
2725 :
2726 : // Original SPW was in reverse order, need to restore that
2727 805 : if (isDescending)
2728 : {
2729 72 : Vector<Double> tempL, tempU;
2730 36 : tempL.assign(newChanLoBound);
2731 36 : tempU.assign(newChanHiBound);
2732 17266 : for (uInt i = 0; i < nc; i++)
2733 : {
2734 17230 : newChanLoBound(i) = tempL(nc - 1 - i);
2735 17230 : newChanHiBound(i) = tempU(nc - 1 - i);
2736 : }
2737 : }
2738 :
2739 805 : message = oss.str();
2740 :
2741 805 : return true;
2742 :
2743 : } // end if (regridQuant== ...
2744 : }
2745 :
2746 : } //# NAMESPACE CASA - END
|