Line data Source code
1 : //# SynthesisUtilMethods.cc:
2 : //# Copyright (C) 2013-2018
3 : //# Associated Universities, Inc. Washington DC, USA.
4 : //#
5 : //# This program is free software; you can redistribute it and/or modify it
6 : //# under the terms of the GNU General Public License as published by the Free
7 : //# Software Foundation; either version 2 of the License, or (at your option)
8 : //# any later version.
9 : //#
10 : //# This program is distributed in the hope that it will be useful, but WITHOUT
11 : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 : //# more details.
14 : //#
15 : //# You should have received a copy of the GNU General Public License along
16 : //# with this program; if not, write to the Free Software Foundation, Inc.,
17 : //# 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 : //#
19 : //# Correspondence concerning AIPS++ should be addressed as follows:
20 : //# Internet email: casa-feedback@nrao.edu.
21 : //# Postal address: AIPS++ Project Office
22 : //# National Radio Astronomy Observatory
23 : //# 520 Edgemont Road
24 : //# Charlottesville, VA 22903-2475 USA
25 : //#
26 : //# $Id$
27 :
28 : #include <casacore/casa/Exceptions/Error.h>
29 : #include <iostream>
30 : #include <sstream>
31 :
32 : #include <casacore/casa/Arrays/Matrix.h>
33 : #include <casacore/casa/Arrays/ArrayMath.h>
34 : #include <casacore/casa/Arrays/ArrayLogical.h>
35 :
36 : #include <casacore/casa/Logging.h>
37 : #include <casacore/casa/Logging/LogIO.h>
38 : #include <casacore/casa/Logging/LogMessage.h>
39 : #include <casacore/casa/Logging/LogSink.h>
40 : #include <casacore/casa/Logging/LogMessage.h>
41 :
42 : #include <casacore/casa/OS/DirectoryIterator.h>
43 : #include <casacore/casa/OS/File.h>
44 : #include <casacore/casa/OS/Path.h>
45 :
46 : #include <casacore/casa/OS/HostInfo.h>
47 :
48 : #include <casacore/images/Images/TempImage.h>
49 : #include <casacore/images/Images/SubImage.h>
50 : #include <casacore/images/Regions/ImageRegion.h>
51 : #include <imageanalysis/Utilities/SpectralImageUtil.h>
52 : #include <casacore/measures/Measures/MeasTable.h>
53 : #include <casacore/measures/Measures/MRadialVelocity.h>
54 : #include <casacore/ms/MSSel/MSSelection.h>
55 : #include <casacore/ms/MeasurementSets/MSColumns.h>
56 : #include <casacore/ms/MeasurementSets/MSDopplerUtil.h>
57 : #include <casacore/tables/Tables/Table.h>
58 : #include <synthesis/ImagerObjects/SynthesisUtilMethods.h>
59 : #include <synthesis/TransformMachines2/Utils.h>
60 :
61 : #include <mstransform/MSTransform/MSTransformRegridder.h>
62 : #include <msvis/MSVis/MSUtil.h>
63 : #include <msvis/MSVis/VisibilityIteratorImpl2.h>
64 : #include <msvis/MSVis/VisBufferUtil.h>
65 : #include <sys/types.h>
66 : #include <unistd.h>
67 : #include <limits>
68 : #include <tuple>
69 : #include <sys/time.h>
70 : #include<sys/resource.h>
71 :
72 : #include <synthesis/ImagerObjects/SIImageStore.h>
73 : #include <synthesis/ImagerObjects/SIImageStoreMultiTerm.h>
74 :
75 : using namespace std;
76 :
77 : using namespace casacore;
78 : namespace casa { //# NAMESPACE CASA - BEGIN
79 :
80 : casacore::String SynthesisUtilMethods::g_hostname;
81 : casacore::String SynthesisUtilMethods::g_startTimestamp;
82 : const casacore::String SynthesisUtilMethods::g_enableOptMemProfile =
83 : "synthesis.imager.memprofile.enable";
84 :
85 1437 : SynthesisUtilMethods::SynthesisUtilMethods()
86 : {
87 :
88 1437 : }
89 :
90 1437 : SynthesisUtilMethods::~SynthesisUtilMethods()
91 : {
92 1437 : }
93 :
94 0 : Int SynthesisUtilMethods::validate(const VisBuffer& vb)
95 : {
96 0 : Int N=vb.nRow(),M=-1;
97 0 : for(Int i=0;i<N;i++)
98 : {
99 0 : if ((!vb.flagRow()(i)) && (vb.antenna1()(i) != vb.antenna2()(i)))
100 0 : {M++;break;}
101 : }
102 0 : return M;
103 : }
104 :
105 508869 : Int SynthesisUtilMethods::validate(const vi::VisBuffer2& vb)
106 : {
107 508869 : Int N=vb.nRows(),M=-1;
108 2257957 : for(Int i=0;i<N;i++)
109 : {
110 2257957 : if ((!vb.flagRow()(i)) && (vb.antenna1()(i) != vb.antenna2()(i)))
111 508869 : {M++;break;}
112 : }
113 508869 : return M;
114 : }
115 : // Get the next largest even composite of 2,3,5.
116 : // This is to ensure a 'good' image size for FFTW.
117 : // Translated from gcwrap/scripts/cleanhelper.py : getOptimumSize
118 3694 : Int SynthesisUtilMethods::getOptimumSize(const Int npix)
119 : {
120 3694 : Int n=npix;
121 :
122 3694 : if( n%2 !=0 ){ n+= 1; }
123 :
124 3694 : Vector<uInt> fac = primeFactors(n, false);
125 : Int val, newlarge;
126 23981 : for( uInt k=0; k< fac.nelements(); k++ )
127 : {
128 20287 : if( fac[k]>5 )
129 : {
130 147 : val = fac[k];
131 301 : while( max( primeFactors(val) ) > 5 ){ val+=1;}
132 147 : fac[k] = val;
133 : }
134 : }
135 3694 : newlarge=product(fac);
136 3951 : for( Int k=n; k<newlarge; k+=2 )
137 : {
138 272 : if( max( primeFactors(k) ) < 6 ) {return k;}
139 : }
140 3679 : return newlarge;
141 3694 : }
142 :
143 : // Return the prime factors of the given number
144 4267 : Vector<uInt> SynthesisUtilMethods::primeFactors(uInt n, Bool /*douniq*/)
145 : {
146 4267 : Vector<uInt> factors;
147 :
148 4267 : Int lastresult = n;
149 4267 : Int sqlast = int(sqrt(n))+1;
150 :
151 4267 : if(n==1){ factors.resize(1);factors[0]=1;return factors;}
152 4267 : Int c=2;
153 : while(1)
154 : {
155 25960 : if( lastresult == 1 || c > sqlast ) { break; }
156 21693 : sqlast = (Int)(sqrt(lastresult))+1;
157 : while(1)
158 : {
159 31323 : if( c>sqlast){ c=lastresult; break; }
160 28058 : if( lastresult % c == 0 ) { break; }
161 9630 : c += 1;
162 : }
163 21693 : factors.resize( factors.nelements()+1, true );
164 21693 : factors[ factors.nelements()-1 ] = c;
165 21693 : lastresult /= c;
166 : }
167 4267 : if( factors.nelements()==0 ) { factors.resize(1);factors[0]=n; }
168 :
169 : //if( douniq ) { factors = unique(factors); }
170 :
171 : /*
172 : /// The Sort::unique isn't working as called below. Results appear to be the
173 : /// same as with the cleanhelper python code, so leaving as is for not. CAS-7889
174 : if( douniq )
175 : {
176 : cout << "Test unique fn on : " << factors << endl;
177 : Sort srt;
178 : Vector<uInt> unvec=factors; uInt nrec;
179 : srt.unique(unvec,nrec);
180 : cout << " Unique : " << unvec << " nr : " << nrec << endl;
181 : }
182 : */
183 :
184 4267 : return factors;
185 0 : }
186 :
187 :
188 35 : Bool SynthesisUtilMethods::fitPsfBeam(const String& imagename, const Int nterms, const Float psfcutoff)
189 : {
190 70 : LogIO os(LogOrigin("SynthesisUtilMethods", "fitPsfBeam"));
191 :
192 35 : if (psfcutoff >=1.0 || psfcutoff<=0.0)
193 : {
194 0 : os << "psfcutoff must be >0 and <1" << LogIO::WARN;
195 0 : return false;
196 : }
197 :
198 35 : std::shared_ptr<SIImageStore> imstore;
199 35 : if( nterms>1 )
200 10 : { imstore = std::shared_ptr<SIImageStore>(new SIImageStoreMultiTerm( imagename, nterms, true, true )); }
201 : else
202 25 : { imstore = std::shared_ptr<SIImageStore>(new SIImageStore( imagename, true, true )); }
203 :
204 :
205 35 : os << "Fitting PSF beam for Imagestore : " << imstore->getName() << LogIO::POST;
206 :
207 35 : imstore->makeImageBeamSet(psfcutoff, true);
208 :
209 35 : imstore->printBeamSet();
210 :
211 35 : imstore->releaseLocks();
212 :
213 35 : return true;
214 35 : }
215 :
216 :
217 :
218 : // Evaluate a polynomial from Taylor coefficients and expand to a Cube.
219 : // Since this funcion is primarily for use with mtmfs_via_cube, this step applies only to
220 : // the multiterm.model.ttx images and the cube.model image cube.
221 18 : Bool SynthesisUtilMethods::taylorCoeffsToCube(const String& cubename,const String& mtname, const Int nterms, const String& reffreq)
222 : {
223 36 : LogIO os(LogOrigin("SynthesisUtilMethods", "taylorCoeffsToCube"));
224 :
225 : // Set up imstores
226 18 : CountedPtr<SIImageStore> cube_imstore;
227 18 : cube_imstore = CountedPtr<SIImageStore>(new SIImageStore( cubename, true, true ));
228 :
229 18 : CountedPtr<SIImageStoreMultiTerm> mt_imstore;
230 18 : mt_imstore = CountedPtr<SIImageStoreMultiTerm>(new SIImageStoreMultiTerm( mtname, nterms, true, true ));
231 :
232 : // Check that .model exists.
233 : try{
234 18 : cube_imstore->model();
235 54 : for(Int i=0;i<nterms;i++)
236 36 : mt_imstore->model(i);
237 : }
238 0 : catch(AipsError &x)
239 : {
240 0 : throw( AipsError("Error in reading image : " + x.getMesg() + "\nModel images must exist on disk." ));
241 0 : }
242 :
243 : // Get/check shapes
244 18 : IPosition cube_shp( cube_imstore->model()->shape() );
245 18 : IPosition mt_shp( mt_imstore->model(0)->shape() );
246 18 : if( cube_shp[0] != mt_shp[0] || cube_shp[1] != mt_shp[1] ||cube_shp[2] != mt_shp[2] ){
247 0 : throw( AipsError("The Cube and Multi-Term images should have the same nx, ny and npol"));
248 : }
249 :
250 : // Read reference frequency
251 18 : Quantity reffreq_qa;
252 18 : Quantity::read( reffreq_qa, reffreq );
253 18 : Double refval = reffreq_qa.getValue("Hz");
254 :
255 : //cout << "ref freq : " << refval << endl;
256 :
257 : //Get the frequency list for the cube
258 18 : CoordinateSystem csys ( cube_imstore->getCSys() );
259 18 : Vector<Double> freqlist( cube_shp[3] );
260 :
261 72 : for(uInt i=0; i<csys.nCoordinates(); i++)
262 : {
263 54 : if( csys.type(i) == Coordinate::SPECTRAL )
264 : {
265 18 : SpectralCoordinate speccoord(csys.spectralCoordinate(i));
266 :
267 108 : for(Int ch=0;ch<cube_shp[3];ch++)
268 : {
269 : Double freq;
270 90 : Bool ret = speccoord.toWorld( freq, ch );
271 90 : if(ret==False) throw(AipsError("Cannot read channel frequency"));
272 90 : freqlist[ch] = freq;
273 :
274 : //cout << "freq " << ch << " is " << freq << endl;
275 : }
276 :
277 18 : }
278 : }
279 :
280 :
281 : // Reset the Cube values to zero.
282 : //cube_imstore->model()->set(0.0);
283 :
284 : //For each pol, do the Taylor-to-Cube calculation.
285 36 : for(Int pol=0; pol<cube_shp[2]; pol++)
286 : {
287 18 : Vector< CountedPtr <ImageInterface<Float> > > mt_subims(nterms);
288 54 : for(Int i=0;i<nterms;i++)
289 : {
290 72 : mt_subims[i] = mt_imstore->makeSubImage(0,1,
291 36 : 0, cube_shp[3],
292 36 : pol, cube_shp[2],
293 108 : *mt_imstore->model(i) );
294 : }
295 :
296 108 : for(Int chan=0; chan<cube_shp[3]; chan++)
297 : {
298 180 : CountedPtr<ImageInterface<Float> > cube_subim=cube_imstore->makeSubImage(0,1,
299 90 : chan, cube_shp[3],
300 90 : pol, cube_shp[2],
301 180 : *cube_imstore->model() );
302 :
303 90 : Double wt = (freqlist[chan] - refval) / refval;
304 :
305 90 : cube_subim->set(0.0);
306 270 : for(Int tt=0;tt<nterms;tt++)
307 : {
308 180 : Double fac = pow(wt,tt);
309 360 : LatticeExpr<Float> oneterm = LatticeExpr<Float>( *cube_subim + (fac) * (*mt_subims[tt])) ;
310 180 : cube_subim->copyData(oneterm);
311 180 : }
312 :
313 :
314 90 : }//for chan
315 18 : }// for pol
316 :
317 18 : return True;
318 :
319 18 : }//end of func
320 :
321 :
322 : // Calculate the RHS of the Normal equations for a linear least squares fit of a Taylor polynomial (per pixel).
323 : // This function is primarily for use with mtmfs_via_cube, and may be used for the PSF (2nterms-1), the residual (nterms)
324 : // and the primary beam (nterms=1).
325 : // imtype=0 : PSF with 2nterms-1 terms
326 : // imtype=1 : residual with nterms terms
327 : // imtype=2 : pb with 1 term
328 : // imtype=3 : sumwt with 2nterms-1 terms
329 53 : Bool SynthesisUtilMethods::cubeToTaylorSum(const String& cubename,const String& mtname, const Int nterms, const String& reffreq, const Int imtype, const Float pblimit)
330 : {
331 106 : LogIO os(LogOrigin("SynthesisUtilMethods", "cubeToTaylorSum"));
332 :
333 : //cout << "imtype : " << imtype << endl;
334 53 : if(imtype <0 || imtype >3)
335 : {
336 0 : throw( AipsError("cubeToTaylorSum currently only supports 'psf','residual','pb', 'sumwt' options"));
337 : }
338 :
339 : // Set up imstores
340 53 : CountedPtr<SIImageStore> cube_imstore;
341 53 : cube_imstore = CountedPtr<SIImageStore>(new SIImageStore( cubename, true, true ));
342 :
343 53 : CountedPtr<SIImageStoreMultiTerm> mt_imstore;
344 53 : mt_imstore = CountedPtr<SIImageStoreMultiTerm>(new SIImageStoreMultiTerm( mtname, nterms, true, true ));
345 : //For psf avg pb has to be done already
346 : // doing residual too for sensitivity this is independent of beam spectral index removal
347 53 : Float maxPB=1.0;
348 53 : if(imtype < 2){
349 70 : LatticeExprNode elnod( max( *(mt_imstore->pb(0)) ) );
350 35 : maxPB=elnod.getFloat();
351 35 : if(maxPB == 0.0){
352 0 : throw(AipsError("Programmers error: should do tt psf images after making average PB"));
353 :
354 : }
355 :
356 35 : }
357 : // cerr << "imtype " << imtype << " MAX PB " << maxPB << endl;
358 : // If dopsf=True, calculate 2n-1 terms.
359 53 : Int out_nterms=nterms; // for residual
360 53 : if(imtype==0 || imtype==3){out_nterms=2 * nterms - 1;} // the psfs fill the upper triangle of the Hessian with 2 nterms-1 elements. Also sumwt.
361 53 : if(imtype==2){out_nterms=1;} // For the PB, for mtmfs_via_cube, we need only tt0. Later, if we need all terms to calculate PB alpha, then change this to nterms, and add the invHesian math (elsewhere) to later convert the RHS vector into the coefficients.
362 :
363 53 : CountedPtr <ImageInterface<Float> > use_cube, use_mt;
364 : // If dopsf=True, check that .psf cube and mt's exist. If dopsf=False, check residual images.
365 : try{
366 53 : switch(imtype)
367 : {
368 9 : case 0: use_cube=cube_imstore->psf();break;
369 26 : case 1: use_cube=cube_imstore->residual();break;
370 9 : case 2: use_cube=cube_imstore->pb();break;
371 9 : case 3: use_cube=cube_imstore->sumwt();break;
372 : }
373 53 : cube_imstore->sumwt();
374 168 : for(Int i=0;i<out_nterms;i++)
375 : {
376 115 : switch(imtype)
377 : {
378 27 : case 0:mt_imstore->psf(i);break;
379 52 : case 1:mt_imstore->residual(i);break;
380 9 : case 2:mt_imstore->pb(i);break;
381 27 : case 3:mt_imstore->sumwt(i);break;
382 : }
383 : }
384 : }
385 0 : catch(AipsError &x)
386 : {
387 0 : throw( AipsError("Error in reading image : " + x.getMesg() + "\n " + imtype + " images must exist on disk." ));
388 0 : }
389 :
390 : // Get/check shapes ( Assume that the PSF always exists in the imstore... A valid assumption in the context of mtmfs_via_cube )
391 106 : IPosition cube_shp( cube_imstore->psf()->shape() );
392 106 : IPosition mt_shp( mt_imstore->psf(0)->shape() );
393 53 : if( cube_shp[0] != mt_shp[0] || cube_shp[1] != mt_shp[1] ||cube_shp[2] != mt_shp[2] ){
394 0 : throw( AipsError("The Cube and Multi-Term images should have the same nx, ny and npol"));
395 : }
396 :
397 : // Read reference frequency
398 106 : Quantity reffreq_qa;
399 53 : Quantity::read( reffreq_qa, reffreq );
400 53 : Double refval = reffreq_qa.getValue("Hz");
401 :
402 : //cout << "ref freq : " << refval << endl;
403 :
404 : //Get the frequency list for the cube
405 106 : CoordinateSystem csys ( cube_imstore->getCSys() );
406 106 : Vector<Double> freqlist( cube_shp[3] );
407 :
408 212 : for(uInt i=0; i<csys.nCoordinates(); i++)
409 : {
410 159 : if( csys.type(i) == Coordinate::SPECTRAL )
411 : {
412 53 : SpectralCoordinate speccoord(csys.spectralCoordinate(i));
413 :
414 324 : for(Int ch=0;ch<cube_shp[3];ch++)
415 : {
416 : Double freq;
417 271 : Bool ret = speccoord.toWorld( freq, ch );
418 271 : if(ret==False) throw(AipsError("Cannot read channel frequency"));
419 271 : freqlist[ch] = freq;
420 : // cout << "freq " << ch << " is " << freq << endl;
421 : }
422 :
423 53 : }
424 : }
425 :
426 :
427 : // Reset the Taylor Sum values to zero.
428 168 : for(Int i=0;i<out_nterms;i++)
429 : {
430 115 : switch(imtype)
431 : {
432 27 : case 0:mt_imstore->psf(i)->set(0.0);break;
433 52 : case 1:mt_imstore->residual(i)->set(0.0);break;
434 9 : case 2:mt_imstore->pb(i)->set(0.0);break;
435 27 : case 3:mt_imstore->sumwt(i)->set(0.0);break;
436 : }
437 : }
438 :
439 : // Get the sumwt spectrum.
440 106 : Array<Float> lsumwt;
441 53 : cube_imstore->sumwt()->get(lsumwt, False);
442 :
443 : // Sum the weights ( or just use accumulate...)
444 106 : LatticeExprNode msum( sum( *cube_imstore->sumwt() ) );
445 53 : Float wtsum = msum.getFloat();
446 :
447 : //cerr << "perchansumwt : shape "<< lsumwt.shape() << " " << lsumwt << " sumwt "<< wtsum << endl;
448 :
449 : //Float wtsum = cube_shp[3]; // This is sum of weights, if all weights are 1.0
450 :
451 : //For each pol, do the Cube-To-Taylor calculation.
452 106 : for(Int pol=0; pol<cube_shp[2]; pol++)
453 : {
454 53 : Vector< CountedPtr <ImageInterface<Float> > > mt_subims(out_nterms);
455 168 : for(Int i=0;i<out_nterms;i++)
456 : {
457 115 : switch(imtype)
458 : {
459 27 : case 0:use_mt=mt_imstore->psf(i);break;
460 52 : case 1:use_mt=mt_imstore->residual(i);break;
461 9 : case 2:use_mt=mt_imstore->pb(i);break;
462 27 : case 3:use_mt=mt_imstore->sumwt(i);break;
463 : }
464 345 : mt_subims[i] = mt_imstore->makeSubImage(0,1,
465 115 : 0, cube_shp[3],
466 115 : pol, cube_shp[2],
467 230 : *use_mt );
468 : }
469 :
470 324 : for(Int chan=0; chan<cube_shp[3]; chan++)
471 : {
472 271 : CountedPtr<ImageInterface<Float> > cube_subim=cube_imstore->makeSubImage(0,1,
473 271 : chan, cube_shp[3],
474 271 : pol, cube_shp[2],
475 271 : *use_cube);
476 271 : if(imtype < 2){
477 358 : CountedPtr<ImageInterface<Float> > pb_subim=cube_imstore->makeSubImage(0,1,
478 179 : chan, cube_shp[3],
479 179 : pol, cube_shp[2],
480 358 : *(cube_imstore->pb()));
481 358 : CountedPtr<ImageInterface<Float> > tmplat = new TempImage<Float>(cube_subim->shape(), cube_subim->coordinates());
482 179 : tmplat->copyData(LatticeExpr<Float>((*pb_subim) *(*cube_subim)));
483 179 : cube_subim = tmplat;
484 :
485 179 : }
486 :
487 271 : IPosition pos(4,0,0,pol,chan);
488 :
489 271 : Double wt = (freqlist[chan] - refval) / refval;
490 :
491 859 : for(Int tt=0;tt<out_nterms;tt++)
492 : {
493 588 : Double fac = pow(wt,tt);
494 : //cerr << "BEF accum " << max(mt_subims[tt]->get()) << " for imtype " << imtype << endl;
495 1176 : LatticeExpr<Float> eachterm = LatticeExpr<Float>( (*mt_subims[tt]) + ((fac) * (*cube_subim) * lsumwt(pos))) ;
496 588 : mt_subims[tt]->copyData(eachterm);
497 : //cerr <<" AFT accum : chan " << chan << " tt " << tt << " fac " << fac << " lsumwt " << lsumwt(pos) << " pos " << pos << " max " << max(mt_subims[tt]->get()) << endl;
498 588 : }
499 :
500 :
501 271 : }//for chan
502 :
503 :
504 : // Divide by sum of weights.
505 168 : for(Int tt=0;tt<out_nterms;tt++)
506 : {
507 : //cerr << "bef div : tt " << tt << " : " << max(mt_subims[tt]->get()) << " for imtype " << imtype << endl;
508 :
509 115 : LatticeExpr<Float> eachterm;
510 115 : if (imtype < 2) {
511 79 : eachterm = LatticeExpr<Float>( iif( (*(mt_imstore->pb(0))) > pblimit , (*mt_subims[tt]) / wtsum/(*(mt_imstore->pb(0))), 0.0));
512 : }
513 : else{
514 36 : eachterm = LatticeExpr<Float>( (*mt_subims[tt]) / wtsum ) ;
515 : }
516 115 : mt_subims[tt]->copyData(eachterm);
517 :
518 115 : mt_subims[tt]->flush();
519 : // cerr << "aft div : " << max(mt_subims[tt]->get()) << endl;
520 115 : }
521 :
522 53 : }// for pol
523 :
524 :
525 : // Set the T/F mask, for PB images. Without this, the PB is fully masked, for aproj /mosaic gridders.
526 53 : if( imtype==2 )
527 : {
528 9 : mt_imstore->removeMask( mt_imstore->pb(0) );
529 : {
530 : //MSK//
531 18 : LatticeExpr<Bool> pbmask( iif( *mt_imstore->pb(0) > fabs(pblimit) , True , False ) );
532 : //MSK//
533 9 : mt_imstore->createMask( pbmask, mt_imstore->pb(0) );
534 9 : mt_imstore->pb(0)->pixelMask().unlock();
535 9 : }
536 :
537 : }
538 :
539 106 : return True;
540 :
541 53 : }//end of func
542 :
543 :
544 26 : Bool SynthesisUtilMethods::removeFreqDepPB(const String& cubename, const String& mtname, const Float pblimit)
545 : {
546 52 : LogIO os(LogOrigin("SynthesisUtilMethods", "removeFreqDepPB"));
547 :
548 : // Set up imstores
549 26 : CountedPtr<SIImageStore> cube_imstore;
550 26 : cube_imstore = CountedPtr<SIImageStore>(new SIImageStore( cubename, true, true ));
551 :
552 26 : CountedPtr<SIImageStoreMultiTerm> mt_imstore;
553 26 : mt_imstore = CountedPtr<SIImageStoreMultiTerm>(new SIImageStoreMultiTerm( mtname, 1, true, true ));
554 :
555 : try{
556 26 : cube_imstore->residual(); // Residual Cube
557 26 : cube_imstore->pb(); // PB cube
558 26 : mt_imstore->pb(0); // avgPB in the tt0 pb.
559 : }
560 0 : catch(AipsError &x)
561 : {
562 0 : throw( AipsError("Error in reading image : " + x.getMesg() + "\n Residual cube, PB cube, and multiterm PB.tt0 must exist on disk." ));
563 0 : }
564 :
565 : // Get/check shapes
566 26 : IPosition cube_shp( cube_imstore->residual()->shape() );
567 26 : IPosition mt_shp( mt_imstore->pb(0)->shape() );
568 26 : if( cube_shp[0] != mt_shp[0] || cube_shp[1] != mt_shp[1] ||cube_shp[2] != mt_shp[2] ){
569 0 : throw( AipsError("The Cube and Multi-Term images should have the same nx, ny and npol"));
570 : }
571 :
572 : //For each pol, do the freq-dep PB math.//////////////////////////
573 52 : for(Int pol=0; pol<cube_shp[2]; pol++)
574 : {
575 :
576 52 : CountedPtr<ImageInterface<Float> > mt_subim = mt_imstore->makeSubImage(0,1,
577 26 : 0, cube_shp[3],
578 26 : pol, cube_shp[2],
579 52 : (*mt_imstore->pb(0)) );
580 :
581 26 : LatticeExprNode mtpbmax( max( *mt_subim ) );
582 26 : Float mtpbmaxval = mtpbmax.getFloat();
583 26 : if(mtpbmaxval <=0.0){os << LogIO::WARN << "pb.tt0 max is < or = zero" << LogIO::POST;}
584 :
585 :
586 159 : for(Int chan=0; chan<cube_shp[3]; chan++)
587 : {
588 266 : CountedPtr<ImageInterface<Float> > cube_subim=cube_imstore->makeSubImage(0,1,
589 133 : chan, cube_shp[3],
590 133 : pol, cube_shp[2],
591 266 : *cube_imstore->residual() );
592 266 : CountedPtr<ImageInterface<Float> > pb_subim=cube_imstore->makeSubImage(0,1,
593 133 : chan, cube_shp[3],
594 133 : pol, cube_shp[2],
595 266 : *cube_imstore->pb() );
596 :
597 133 : LatticeExprNode pbmax( max( *pb_subim ) );
598 133 : Float pbmaxval = pbmax.getFloat();
599 133 : if( pbmaxval<=0.0 )
600 : {
601 0 : os << LogIO::WARN << "pb max is zero for chan" << chan << LogIO::POST;
602 : }
603 : else
604 : {
605 266 : LatticeExpr<Float> thepbcor( iif( *(pb_subim) > pblimit , (*mt_subim)*(*(cube_subim))/(*(pb_subim)) , 0.0 ) );
606 133 : cube_subim->copyData( thepbcor );
607 133 : }// if not zero
608 :
609 133 : }//for chan
610 26 : }// for pol
611 :
612 26 : return True;
613 :
614 26 : }//end of func
615 :
616 :
617 :
618 18 : Bool SynthesisUtilMethods::applyFreqDepPB(const String& cubename, const String& mtname, const Float pblimit)
619 : {
620 36 : LogIO os(LogOrigin("SynthesisUtilMethods", "applyFreqDepPB"));
621 :
622 : // Set up imstores
623 18 : CountedPtr<SIImageStore> cube_imstore;
624 18 : cube_imstore = CountedPtr<SIImageStore>(new SIImageStore( cubename, true, true ));
625 :
626 18 : CountedPtr<SIImageStoreMultiTerm> mt_imstore;
627 18 : mt_imstore = CountedPtr<SIImageStoreMultiTerm>(new SIImageStoreMultiTerm( mtname, 1, true, true ));
628 :
629 : try{
630 18 : cube_imstore->model(); // Model Cube
631 18 : cube_imstore->pb(); // PB cube
632 18 : mt_imstore->pb(0); // avgPB in the tt0 pb.
633 : }
634 0 : catch(AipsError &x)
635 : {
636 0 : throw( AipsError("Error in reading image : " + x.getMesg() + "\n Model cube, PB cube, and multiterm PB.tt0 must exist on disk." ));
637 0 : }
638 :
639 : // Get/check shapes
640 18 : IPosition cube_shp( cube_imstore->model()->shape() );
641 18 : IPosition mt_shp( mt_imstore->pb(0)->shape() );
642 18 : if( cube_shp[0] != mt_shp[0] || cube_shp[1] != mt_shp[1] ||cube_shp[2] != mt_shp[2] ){
643 0 : throw( AipsError("The Cube and Multi-Term images should have the same nx, ny and npol"));
644 : }
645 :
646 : //For each pol, do the freq-dep PB math.//////////////////////////
647 36 : for(Int pol=0; pol<cube_shp[2]; pol++)
648 : {
649 36 : CountedPtr<ImageInterface<Float> > mt_subim = mt_imstore->makeSubImage(0,1,
650 18 : 0, cube_shp[3],
651 18 : pol, cube_shp[2],
652 36 : (*mt_imstore->pb(0)) );
653 :
654 18 : LatticeExprNode mtpbmax( max( *mt_subim ) );
655 18 : Float mtpbmaxval = mtpbmax.getFloat();
656 18 : if(mtpbmaxval <=0.0)
657 0 : {os << LogIO::SEVERE << "pb.tt0 max is < or = zero. Cannot divide model image ! ERROR" << LogIO::POST;}
658 : else
659 : {
660 :
661 108 : for(Int chan=0; chan<cube_shp[3]; chan++)
662 : {
663 180 : CountedPtr<ImageInterface<Float> > cube_subim=cube_imstore->makeSubImage(0,1,
664 90 : chan, cube_shp[3],
665 90 : pol, cube_shp[2],
666 180 : *cube_imstore->model() );
667 180 : CountedPtr<ImageInterface<Float> > pb_subim=cube_imstore->makeSubImage(0,1,
668 90 : chan, cube_shp[3],
669 90 : pol, cube_shp[2],
670 180 : *cube_imstore->pb() );
671 :
672 :
673 90 : LatticeExprNode pbmax( max( *pb_subim ) );
674 90 : Float pbmaxval = pbmax.getFloat();
675 90 : if( pbmaxval<=0.0 )
676 : {
677 0 : os << LogIO::WARN << "pb max is zero for chan" << chan << LogIO::POST;
678 : }
679 : else
680 : {
681 180 : LatticeExpr<Float> thepbcor( iif( *(pb_subim) > pblimit , (*(cube_subim)) *(*(pb_subim)) / (*mt_subim) , 0.0 ) );
682 90 : cube_subim->copyData( thepbcor );
683 90 : }// if not zero
684 :
685 90 : }//for chan
686 : }// if mtpb >0
687 18 : }// for pol
688 :
689 18 : return True;
690 :
691 18 : }//end of func
692 :
693 :
694 :
695 :
696 : /***make a record of synthesisimager::weight parameters***/
697 1628 : Record SynthesisUtilMethods::fillWeightRecord(const String& type, const String& rmode,
698 : const Quantity& noise, const Double robust,
699 : const Quantity& fieldofview,
700 : const Int npixels, const Bool multiField, const Bool useCubeBriggs,
701 : const String& filtertype, const Quantity& filterbmaj,
702 : const Quantity& filterbmin, const Quantity& filterbpa, const Double& fracBW){
703 :
704 1628 : Record outRec;
705 1628 : outRec.define("type", type);
706 1628 : outRec.define("rmode", rmode);
707 1628 : Record quantRec;
708 1628 : QuantumHolder(noise).toRecord(quantRec);
709 1628 : outRec.defineRecord("noise", quantRec);
710 1628 : outRec.define("robust", robust);
711 1628 : QuantumHolder(fieldofview).toRecord(quantRec);
712 1628 : outRec.defineRecord("fieldofview", quantRec);
713 1628 : outRec.define("npixels", npixels);
714 1628 : outRec.define("multifield", multiField);
715 1628 : outRec.define("usecubebriggs", useCubeBriggs);
716 1628 : outRec.define("filtertype", filtertype);
717 1628 : QuantumHolder(filterbmaj).toRecord(quantRec);
718 1628 : outRec.defineRecord("filterbmaj", quantRec);
719 1628 : QuantumHolder(filterbmin).toRecord(quantRec);
720 1628 : outRec.defineRecord("filterbmin", quantRec);
721 1628 : QuantumHolder(filterbpa).toRecord(quantRec);
722 1628 : outRec.defineRecord("filterbpa", quantRec);
723 1628 : outRec.define("fracBW", fracBW);
724 :
725 3256 : return outRec;
726 1628 : }
727 869 : void SynthesisUtilMethods::getFromWeightRecord(String& type, String& rmode,
728 : Quantity& noise, Double& robust,
729 : Quantity& fieldofview,
730 : Int& npixels, Bool& multiField, Bool& useCubeBriggs,
731 : String& filtertype, Quantity& filterbmaj,
732 : Quantity& filterbmin, Quantity& filterbpa, Double& fracBW, const Record& inRec){
733 869 : QuantumHolder qh;
734 869 : String err;
735 869 : if(!inRec.isDefined("type"))
736 0 : throw(AipsError("Record is not filled with SynthesisUtilMethods::fillWeightRecord"));
737 869 : inRec.get("type", type);
738 869 : inRec.get("rmode", rmode);
739 869 : if(!qh.fromRecord(err, inRec.asRecord("noise")))
740 0 : throw(AipsError("Error in reading noise param"));
741 869 : noise=qh.asQuantity();
742 869 : inRec.get("robust", robust);
743 869 : if(!qh.fromRecord(err, inRec.asRecord("fieldofview")))
744 0 : throw(AipsError("Error in reading fieldofview param"));
745 869 : fieldofview=qh.asQuantity();
746 869 : inRec.get("npixels", npixels);
747 869 : inRec.get("multifield", multiField);
748 869 : inRec.get("usecubebriggs", useCubeBriggs);
749 869 : inRec.get("filtertype", filtertype);
750 869 : if(!qh.fromRecord(err, inRec.asRecord("filterbmaj")))
751 0 : throw(AipsError("Error in reading filterbmaj param"));
752 869 : filterbmaj=qh.asQuantity();
753 869 : if(!qh.fromRecord(err, inRec.asRecord("filterbmin")))
754 0 : throw(AipsError("Error in reading filterbmin param"));
755 869 : filterbmin=qh.asQuantity();
756 869 : if(!qh.fromRecord(err, inRec.asRecord("filterbpa")))
757 0 : throw(AipsError("Error in reading filterbpa param"));
758 869 : filterbpa=qh.asQuantity();
759 869 : inRec.get("fracBW", fracBW);
760 :
761 :
762 :
763 869 : }
764 :
765 :
766 : /**
767 : * Get values from lines of a /proc/self/status file. For example:
768 : * 'VmRSS: 600 kB'
769 : * @param str line from status file
770 : * @return integer value (memory amount, etc.)
771 : */
772 0 : Int SynthesisUtilMethods::parseProcStatusLine(const std::string &str) {
773 0 : istringstream is(str);
774 0 : std::string token;
775 0 : is >> token;
776 0 : is >> token;
777 0 : Int value = stoi(token);
778 0 : return value;
779 0 : }
780 :
781 : /**
782 : * Produces a name for a 'memprofile' output file. For example:
783 : * casa.synthesis.imager.memprofile.23514.pc22555.hq.eso.org.20171209_120446.txt
784 : * (where 23514 is the PID passed as input parameter).
785 : *
786 : * @param pid PID of the process running the imager
787 : *
788 : * @return a longish 'memprofile' filename including PID, machine, timestamp, etc.
789 : **/
790 0 : String SynthesisUtilMethods::makeResourceFilename(int pid)
791 : {
792 0 : if (g_hostname.empty() or g_startTimestamp.empty()) {
793 : // TODO: not using HOST_NAME_MAX because of issues with __APPLE__
794 : // somehow tests tAWPFTM, tSynthesisImager, and tSynthesisImagerVi2 fail.
795 0 : const int strMax = 255;
796 : char hostname[strMax];
797 0 : gethostname(hostname, strMax);
798 0 : g_hostname = hostname;
799 :
800 0 : auto time = std::time(nullptr);
801 0 : auto gmt = std::gmtime(&time);
802 0 : const char* format = "%Y%m%d_%H%M%S";
803 : char timestr[strMax];
804 0 : std::strftime(timestr, strMax, format, gmt);
805 0 : g_startTimestamp = timestr;
806 : }
807 :
808 0 : return String("casa.synthesis.imager.memprofile." + String::toString(pid) +
809 0 : "." + g_hostname + "." + g_startTimestamp + ".txt");
810 : }
811 :
812 9 : Bool SynthesisUtilMethods::adviseChanSel(Double& freqStart, Double& freqEnd,
813 : const Double& freqStep, const MFrequency::Types& freqframe,
814 : Vector<Int>& spw, Vector<Int>& start,
815 : Vector<Int>& nchan, const String& ms, const String& ephemtab, const Int field_id, const Bool getFreqRange, const String spwselection){
816 :
817 18 : LogIO os(LogOrigin("SynthesisUtilMethods", "adviseChanSel"));
818 9 : if(ms==String("")){
819 0 : throw(AipsError("Need a valid MS"));
820 : }
821 9 : spw.resize();
822 9 : start.resize();
823 9 : nchan.resize();
824 : try {
825 9 : if(!getFreqRange){
826 0 : Vector<Int> bnchan;
827 0 : Vector<Int> bstart;
828 0 : Vector<Int> bspw;
829 : Double fS, fE;
830 0 : fS=freqStart;
831 0 : fE=freqEnd;
832 0 : if(freqEnd < freqStart){
833 0 : fS=freqEnd;
834 0 : fE=freqStart;
835 : }
836 :
837 :
838 : {
839 :
840 0 : MeasurementSet elms(String(ms), TableLock(TableLock::AutoNoReadLocking), Table::Old);
841 0 : if(ephemtab != "" && freqframe == MFrequency::REST ){
842 0 : MSUtil::getSpwInSourceFreqRange(bspw, bstart, bnchan, elms, fS, fE, fabs(freqStep), ephemtab, field_id);
843 : }
844 : else
845 0 : MSUtil::getSpwInFreqRange(bspw, bstart, bnchan, elms, fS, fE, fabs(freqStep), freqframe, field_id);
846 0 : elms.relinquishAutoLocks(true);
847 :
848 0 : }
849 0 : spw=Vector<Int> (bspw);
850 0 : start=Vector<Int> (bstart);
851 0 : nchan=Vector<Int> (bnchan);
852 0 : }
853 : else{
854 :
855 : {
856 9 : MeasurementSet elms(ms, TableLock(TableLock::AutoNoReadLocking), Table::Old);
857 9 : MSSelection thisSelection;
858 9 : String spsel=spwselection;
859 9 : if(spsel=="")spsel="*";
860 9 : thisSelection.setSpwExpr(spsel);
861 9 : TableExprNode exprNode=thisSelection.toTableExprNode(&elms);
862 9 : Matrix<Int> chanlist=thisSelection.getChanList();
863 9 : if(chanlist.ncolumn() <3){
864 0 : freqStart=-1.0;
865 0 : freqEnd=-1.0;
866 0 : return false;
867 : }
868 9 : Vector<Int> elspw=chanlist.column(0);
869 9 : Vector<Int> elstart=chanlist.column(1);
870 18 : Vector<Int> elnchan=Vector<Int> (chanlist.column(2)-elstart)+1;
871 9 : if(ephemtab != "" ){
872 0 : const MSColumns mscol(ms);
873 0 : MEpoch ep=mscol.timeMeas()(0);
874 0 : Quantity sysvel;
875 0 : String ephemTable("");
876 0 : MDirection::Types mtype=MDirection::APP;
877 0 : MDirection mdir(mtype);
878 0 : if(Table::isReadable(ephemtab)){
879 0 : ephemTable=ephemtab;
880 : }
881 0 : else if(ephemtab=="TRACKFIELD"){
882 0 : ephemTable=(mscol.field()).ephemPath(field_id);
883 : }
884 0 : else if(MDirection::getType(mtype, ephemtab)){
885 0 : mdir=MDirection(mtype);
886 : }
887 :
888 0 : MSUtil::getFreqRangeAndRefFreqShift(freqStart, freqEnd, sysvel, ep, elspw, elstart, elnchan, elms, ephemTable , mdir, True);
889 :
890 0 : }
891 : else
892 9 : MSUtil::getFreqRangeInSpw(freqStart, freqEnd, elspw, elstart, elnchan, elms, freqframe, field_id);
893 9 : }
894 :
895 : }
896 :
897 :
898 :
899 :
900 0 : } catch (AipsError x) {
901 : os << LogIO::SEVERE << "Caught exception: " << x.getMesg()
902 0 : << LogIO::POST;
903 0 : return false;
904 0 : }
905 0 : catch (...){
906 : os << LogIO::SEVERE << "Unknown exception handled"
907 0 : << LogIO::POST;
908 0 : return false;
909 :
910 0 : }
911 :
912 9 : return true;
913 :
914 9 : }
915 :
916 26867 : void SynthesisUtilMethods::getResource(String label, String fname)
917 : {
918 : // TODO: not tested on anything else than LINUX (MACOS for the future)
919 : #if !defined(AIPS_LINUX)
920 : return;
921 : #endif
922 :
923 26867 : Bool isOn = false;
924 26867 : AipsrcValue<Bool>::find(isOn, g_enableOptMemProfile);
925 26867 : if (!isOn)
926 26867 : return;
927 :
928 : // TODO: reorganize, use struct or something to hold and pass info over. ifdef lnx
929 0 : LogIO casalog( LogOrigin("SynthesisUtilMethods", "getResource", WHERE) );
930 :
931 : // To hold memory stats, in MB
932 0 : int vmRSS = -1, vmHWM = -1, vmSize = -1, vmPeak = -1, vmSwap = -1;
933 0 : pid_t pid = -1;
934 0 : int fdSize = -1;
935 :
936 : // TODO: this won't probably work on anything but linux
937 0 : ifstream procFile("/proc/self/status");
938 0 : if (procFile.is_open()) {
939 0 : std::string line;
940 0 : while (not procFile.eof()) {
941 0 : getline(procFile, line);
942 0 : const std::string startVmRSS = "VmRSS:";
943 0 : const std::string startVmWHM = "VmHWM:";
944 0 : const std::string startVmSize = "VmSize:";
945 0 : const std::string startVmPeak = "VmPeak:";
946 0 : const std::string startVmSwap = "VmSwap:";
947 0 : const std::string startFDSize = "FDSize:";
948 0 : const double KB_TO_MB = 1024.0;
949 0 : if (startVmRSS == line.substr(0, startVmRSS.size())) {
950 0 : vmRSS = parseProcStatusLine(line.c_str()) / KB_TO_MB;
951 0 : } else if (startVmWHM == line.substr(0, startVmWHM.size())) {
952 0 : vmHWM = parseProcStatusLine(line.c_str()) / KB_TO_MB;
953 0 : } else if (startVmSize == line.substr(0, startVmSize.size())) {
954 0 : vmSize = parseProcStatusLine(line.c_str()) / KB_TO_MB;
955 0 : } else if (startVmPeak == line.substr(0, startVmPeak.size())) {
956 0 : vmPeak = parseProcStatusLine(line.c_str()) / KB_TO_MB;
957 0 : } else if (startVmSwap == line.substr(0, startVmSwap.size())) {
958 0 : vmSwap = parseProcStatusLine(line.c_str()) / KB_TO_MB;
959 0 : } else if (startFDSize == line.substr(0, startFDSize.size())) {
960 0 : fdSize = parseProcStatusLine(line.c_str());
961 : }
962 0 : }
963 0 : procFile.close();
964 0 : }
965 :
966 0 : pid = getpid();
967 :
968 : struct rusage usage;
969 : struct timeval now;
970 0 : getrusage(RUSAGE_SELF, &usage);
971 0 : now = usage.ru_utime;
972 :
973 : // TODO: check if this works as expected when /proc/self/status is not there
974 : // Not clear at all if VmHWM and .ru_maxrss measure the same thing
975 : // Some alternative is needed for the other fields as well: VmSize, VMHWM, FDSize.
976 0 : if (vmHWM < 0) {
977 0 : vmHWM = usage.ru_maxrss;
978 : }
979 :
980 0 : ostringstream oss;
981 0 : oss << "PID: " << pid ;
982 0 : oss << " MemRSS (VmRSS): " << vmRSS << " MB.";
983 0 : oss << " VmWHM: " << vmHWM << " MB.";
984 0 : oss << " VirtMem (VmSize): " << vmSize << " MB.";
985 0 : oss << " VmPeak: " << vmPeak << " MB.";
986 0 : oss << " VmSwap: " << vmSwap << " MB.";
987 0 : oss << " ProcTime: " << now.tv_sec << '.' << now.tv_usec;
988 0 : oss << " FDSize: " << fdSize;
989 0 : oss << " [" << label << "] ";
990 0 : casalog << oss.str() << LogIO::NORMAL3 << LogIO::POST;
991 :
992 : // Write this to a file too...
993 : try {
994 0 : if (fname.empty()) {
995 0 : fname = makeResourceFilename(pid);
996 : }
997 0 : ofstream ofile(fname, ios::app);
998 0 : if (ofile.is_open()) {
999 0 : if (0 == ofile.tellp()) {
1000 : casalog << g_enableOptMemProfile << " is enabled, initializing output file for "
1001 : "imager profiling information (memory and run time): " << fname <<
1002 0 : LogIO::NORMAL << LogIO::POST;
1003 0 : ostringstream header;
1004 : header << "# PID, MemRSS_(VmRSS)_MB, VmWHM_MB, VirtMem_(VmSize)_MB, VmPeak_MB, "
1005 0 : "VmSwap_MB, ProcTime_sec, FDSize, label_checkpoint";
1006 0 : ofile << header.str() << '\n';
1007 0 : }
1008 0 : ostringstream line;
1009 0 : line << pid << ',' << vmRSS << ',' << vmHWM << ',' << vmSize << ','
1010 0 : << vmPeak << ','<< vmSwap << ',' << now.tv_sec << '.' << now.tv_usec << ','
1011 0 : << fdSize << ',' << '[' << label << ']';
1012 0 : ofile << line.str() << '\n';
1013 0 : ofile.close();
1014 0 : }
1015 0 : } catch(std::runtime_error &exc) {
1016 : casalog << "Could not write imager memory+runtime information into output file: "
1017 0 : << fname << LogIO::WARN << LogIO::POST;
1018 0 : }
1019 0 : }
1020 :
1021 :
1022 : // Data partitioning rules for CONTINUUM imaging
1023 : //
1024 : // ALL members of the selection parameters in selpars are strings
1025 : // ONLY. This methods reads the selection parameters from selpars
1026 : // and returns a partitioned Record with npart data selection
1027 : // entries.
1028 : //
1029 : // The algorithm used to do the partitioning along the TIME axis is
1030 : // as follows:
1031 : //
1032 : // for each MS in selpars
1033 : // - get the selection parameters
1034 : // - generate a selected MS
1035 : // - get number of rows in the selected MS
1036 : // - divide the rows in nparts
1037 : // - for each part
1038 : // - get compute rowBeg and rowEnd
1039 : // - modify rowEnd such that rowEnd points to the end of
1040 : // full integration data. This is done as follows:
1041 : // tRef = TIME(rowEnd);
1042 : // reduce rowEnd till TIME(rowEnd) != tRef
1043 : // - Construct a T0~T1 string
1044 : // - Fill it in the timeSelPerPart[msID][PartNo] array
1045 : //
1046 0 : Record SynthesisUtilMethods::continuumDataPartition(Record &selpars, const Int npart)
1047 : {
1048 0 : LogIO os( LogOrigin("SynthesisUtilMethods","continuumDataPartition",WHERE) );
1049 :
1050 0 : Record onepart, allparts;
1051 0 : Vector<Vector<String> > timeSelPerPart;
1052 0 : timeSelPerPart.resize(selpars.nfields());
1053 :
1054 : // Duplicate the entire input record npart times, with a specific partition id.
1055 : // Modify each sub-record according to partition id.
1056 0 : for (uInt msID=0;msID<selpars.nfields();msID++)
1057 : {
1058 0 : Record thisMS= selpars.subRecord(RecordFieldId("ms"+String::toString(msID)));
1059 0 : String msName = thisMS.asString("msname");
1060 0 : timeSelPerPart[msID].resize(npart,true);
1061 : //
1062 : // Make a selected MS and extract the time-column information
1063 : //
1064 0 : MeasurementSet ms(msName,TableLock(TableLock::AutoNoReadLocking), Table::Old),
1065 0 : selectedMS(ms);
1066 0 : MSInterface msI(ms); MSSelection msSelObj;
1067 0 : msSelObj.reset(msI,MSSelection::PARSE_NOW,
1068 : thisMS.asString("timestr"),
1069 : thisMS.asString("antenna"),
1070 : thisMS.asString("field"),
1071 : thisMS.asString("spw"),
1072 : thisMS.asString("uvdist"),
1073 : thisMS.asString("taql"),
1074 : "",//thisMS.asString("poln"),
1075 : thisMS.asString("scan"),
1076 : "",//thisMS.asString("array"),
1077 : thisMS.asString("state"),
1078 : thisMS.asString("obs")//observation
1079 : );
1080 0 : msSelObj.getSelectedMS(selectedMS);
1081 :
1082 : //--------------------------------------------------------------------
1083 : // Use the selectedMS to generate time selection strings per part
1084 : //
1085 : // Double Tint;
1086 0 : MSMainColumns mainCols(selectedMS);
1087 0 : Vector<rownr_t> rowNumbers = selectedMS.rowNumbers();
1088 0 : Int nRows=selectedMS.nrow(),
1089 0 : dRows=nRows/npart;
1090 0 : Int rowBegID=0, rowEndID=nRows-1;
1091 0 : Int rowBeg=rowNumbers[rowBegID], rowEnd=rowNumbers[rowEndID];
1092 : //cerr << "NRows, dRows, npart = " << nRows << " " << dRows << " " << npart << " " << rowBeg << " " << rowEnd << endl;
1093 :
1094 0 : rowEndID = rowBegID + dRows;
1095 :
1096 :
1097 0 : MVTime mvInt=mainCols.intervalQuant()(0);
1098 : //Time intT(mvInt.getTime());
1099 : // Tint = intT.modifiedJulianDay();
1100 :
1101 0 : Int partNo=0;
1102 : // The +1 in rowBeg and rowEnd below is because it appears
1103 : // that TaQL by default counts from 1, not 0.
1104 0 : while(rowEndID < nRows)
1105 : {
1106 : // rowBeg=rowNumbers[rowBegID]; rowEnd = rowNumbers[rowEndID];
1107 0 : rowBeg=rowBegID+1; rowEnd = rowEndID+1;
1108 0 : stringstream taql;
1109 0 : taql << "ROWNUMBER() >= " << rowBeg << " && ROWNUMBER() <= " << rowEnd;
1110 0 : timeSelPerPart[msID][partNo] = taql.str();
1111 :
1112 0 : if (partNo == npart - 1) break;
1113 0 : partNo++;
1114 0 : rowBegID = rowEndID+1;
1115 0 : rowEndID = min(rowBegID + dRows, nRows-1);
1116 0 : if (rowEndID == nRows-1) break;
1117 0 : }
1118 :
1119 : //rowBeg=rowNumbers[rowBegID]; rowEnd = rowNumbers[nRows-1];
1120 0 : stringstream taql;
1121 0 : rowBeg=rowBegID+1; rowEnd = nRows-1+1;
1122 0 : taql << "ROWNUMBER() >= " << rowBeg << " && ROWNUMBER() <= " << rowEnd;
1123 0 : timeSelPerPart[msID][partNo] = taql.str();
1124 : os << endl << "Rows = " << rowBeg << " " << rowEnd << " "
1125 0 : << "[P][M]: " << msID << ":" << partNo << " " << timeSelPerPart[msID][partNo]
1126 0 : << LogIO::POST;
1127 0 : }
1128 : //
1129 : // The time selection strings for all parts of the current
1130 : // msID are in timeSelPerPart.
1131 : //--------------------------------------------------------------------
1132 : //
1133 : // Now reverse the order of parts and ME loops. Create a Record
1134 : // per part, get the MS for thisPart. Put the associated time
1135 : // selection string in it. Add the thisMS to thisPart Record.
1136 : // Finally add thisPart Record to the allparts Record.
1137 : //
1138 0 : for(Int iPart=0; iPart<npart; iPart++)
1139 : {
1140 0 : Record thisPart;
1141 0 : thisPart.assign(selpars);
1142 0 : for (uInt msID=0; msID<selpars.nfields(); msID++)
1143 : {
1144 0 : Record thisMS = thisPart.subRecord(RecordFieldId("ms"+String::toString(msID)));
1145 :
1146 0 : thisMS.define("taql",timeSelPerPart[msID][iPart]);
1147 0 : thisPart.defineRecord(RecordFieldId("ms"+String::toString(msID)) , thisMS);
1148 0 : }
1149 0 : allparts.defineRecord(RecordFieldId(String::toString(iPart)), thisPart);
1150 0 : }
1151 : // cerr << allparts << endl;
1152 0 : return allparts;
1153 :
1154 : // for( Int part=0; part < npart; part++)
1155 : // {
1156 :
1157 : // onepart.assign(selpars);
1158 :
1159 :
1160 : // //-------------------------------------------------
1161 : // // WARNING : This is special-case code for two specific datasets
1162 : // for ( uInt msid=0; msid<selpars.nfields(); msid++)
1163 : // {
1164 : // Record onems = onepart.subRecord( RecordFieldId("ms"+String::toString(msid)) );
1165 : // String msname = onems.asString("msname");
1166 : // String spw = onems.asString("spw");
1167 : // if(msname.matches("DataTest/twopoints_twochan.ms"))
1168 : // {
1169 : // onems.define("spw", spw+":"+String::toString(part));
1170 : // }
1171 : // if(msname.matches("DataTest/point_twospws.ms"))
1172 : // {
1173 : // onems.define("spw", spw+":"+ (((Bool)part)?("10~19"):("0~9")) );
1174 : // }
1175 : // if(msname.matches("DataTest/reg_mawproject.ms"))
1176 : // {
1177 : // onems.define("scan", (((Bool)part)?("1~17"):("18~35")) );
1178 : // }
1179 : // onepart.defineRecord( RecordFieldId("ms"+String::toString(msid)) , onems );
1180 : // }// end ms loop
1181 : // //-------------------------------------------------
1182 :
1183 : // allparts.defineRecord( RecordFieldId(String::toString(part)), onepart );
1184 :
1185 : // }// end partition loop
1186 :
1187 : // return allparts;
1188 0 : }
1189 :
1190 :
1191 : // Data partitioning rules for CUBE imaging
1192 0 : Record SynthesisUtilMethods::cubeDataPartition(const Record &selpars, const Int npart,
1193 : const Double freqBeg, const Double freqEnd, const MFrequency::Types eltype)
1194 : {
1195 0 : LogIO os( LogOrigin("SynthesisUtilMethods","cubeDataPartition",WHERE) );
1196 : // Temporary special-case code. Please replace with actual rules.
1197 0 : Vector<Double> fstart(npart);
1198 0 : Vector<Double> fend(npart);
1199 0 : Double step=(freqEnd-freqBeg)/Double(npart);
1200 0 : fstart(0)=freqBeg;
1201 0 : fend(0)=freqBeg+step;
1202 0 : for (Int k=1; k < npart; ++k){
1203 0 : fstart(k)=fstart(k-1)+step;
1204 0 : fend(k)=fend(k-1)+step;
1205 : }
1206 0 : return cubeDataPartition( selpars, fstart, fend, eltype );
1207 :
1208 0 : }
1209 :
1210 :
1211 0 : Record SynthesisUtilMethods::cubeDataImagePartition(const Record & selpars, const CoordinateSystem&
1212 : incsys, const Int npart, const Int nchannel,
1213 : Vector<CoordinateSystem>& outCsys,
1214 : Vector<Int>& outnChan){
1215 :
1216 0 : LogIO os( LogOrigin("SynthesisUtilMethods","cubeDataImagePartition",WHERE) );
1217 0 : outnChan.resize(npart);
1218 0 : outCsys.resize(npart);
1219 0 : Int nomnchan=nchannel/npart;
1220 0 : outnChan.set(nomnchan);
1221 0 : nomnchan=nchannel%npart;
1222 0 : for (Int k=0; k < nomnchan; ++k)
1223 0 : outnChan[k]+=1;
1224 0 : Vector<Int> shp(0);
1225 : //shp(0)=20; shp(1)=20; shp(2)=1; shp(3)=outnChan[0];
1226 0 : Vector<Float> shift(4, 0.0);
1227 0 : Vector<Float> fac(4, 1.0);
1228 0 : Vector<Double> freqEnd(npart);
1229 0 : Vector<Double> freqStart(npart);
1230 0 : Float chanshift=0.0;
1231 0 : for (Int k =0; k <npart; ++k){
1232 0 : shift(3)=chanshift;
1233 : //cerr << k << " shift " << shift << endl;
1234 0 : outCsys[k]=incsys.subImage(shift, fac, shp);
1235 0 : freqStart[k]=SpectralImageUtil::worldFreq(outCsys[k], 0.0);
1236 0 : freqEnd[k]=SpectralImageUtil::worldFreq(outCsys[k], Double(outnChan[k]-1));
1237 0 : if(freqStart[k] > freqEnd[k]){
1238 0 : Double tmp=freqEnd[k];
1239 0 : freqEnd[k]=freqStart[k];
1240 0 : freqStart[k]=tmp;
1241 : }
1242 0 : chanshift+=Float(outnChan[k]);
1243 : }
1244 0 : MFrequency::Types eltype=incsys.spectralCoordinate(incsys.findCoordinate(Coordinate::SPECTRAL)).frequencySystem(true);
1245 :
1246 : //os << "freqStart="<<freqStart<<" freqend="<<freqEnd<< "eltype="<<eltype<<LogIO::POST;
1247 0 : Record rec=cubeDataPartition(selpars, freqStart, freqEnd, eltype);
1248 0 : for (Int k=0; k < npart ; ++k){
1249 0 : outCsys[k].save(rec.asrwRecord(String::toString(k)), "coordsys");
1250 0 : rec.asrwRecord(String::toString(k)).define("nchan", outnChan[k]);
1251 : }
1252 0 : return rec;
1253 0 : }
1254 :
1255 0 : Record SynthesisUtilMethods::cubeDataPartition(const Record &selpars, const Vector<Double>& freqBeg, const Vector<Double>&freqEnd, const MFrequency::Types eltype){
1256 0 : LogIO os( LogOrigin("SynthesisUtilMethods","cubeDataPartition",WHERE) );
1257 0 : Record retRec;
1258 0 : Int npart=freqBeg.shape()(0);
1259 0 : for (Int k=0; k < npart; ++k){
1260 0 : Int nms=selpars.nfields();
1261 0 : Record partRec;
1262 0 : for(Int j=0; j < nms; ++j){
1263 0 : if(selpars.isDefined(String("ms"+String::toString(j)))){
1264 0 : Record msRec=selpars.asRecord(String("ms"+String::toString(j)));
1265 0 : if(!msRec.isDefined("msname"))
1266 0 : throw(AipsError("No msname key in ms record"));
1267 0 : String msname=msRec.asString("msname");
1268 0 : String userspw=msRec.isDefined("spw")? msRec.asString("spw") : "*";
1269 0 : String userfield=msRec.isDefined("field") ? msRec.asString("field") : "*";
1270 0 : String userstate=msRec.isDefined("state") ? msRec.asString("state") : "*";
1271 :
1272 0 : MeasurementSet elms(msname);
1273 0 : Record laSelection=elms.msseltoindex(userspw, userfield);
1274 0 : if (userfield=="") userfield="*";
1275 0 : MSSelection mssel;
1276 0 : mssel.setSpwExpr(userspw);
1277 0 : mssel.setFieldExpr(userfield);
1278 0 : mssel.setStateExpr(userstate);
1279 0 : TableExprNode exprNode = mssel.toTableExprNode(&elms);
1280 0 : Matrix<Int> spwsel=mssel.getChanList();
1281 0 : Vector<Int> fieldsel=mssel.getFieldList();
1282 : // case for scan intent specified
1283 0 : if (userstate!="*") {
1284 0 : MeasurementSet elselms((elms)(exprNode), &elms);
1285 0 : MSColumns tmpmsc(elselms);
1286 0 : Vector<Int> fldidv=tmpmsc.fieldId().getColumn();
1287 0 : if (fldidv.nelements()==0)
1288 0 : throw(AipsError("No field ids were selected, please check input parameters"));
1289 0 : std::set<Int> ufldids(fldidv.begin(),fldidv.end());
1290 0 : std::vector<Int> tmpv(ufldids.begin(), ufldids.end());
1291 0 : fieldsel.resize(tmpv.size());
1292 0 : uInt count=0;
1293 0 : for (std::vector<int>::const_iterator it=tmpv.begin();it != tmpv.end(); it++)
1294 : {
1295 0 : fieldsel(count) = *it;
1296 0 : count++;
1297 : }
1298 0 : }
1299 : //Matrix<Int> spwsel=laSelection.asArrayInt("channel");
1300 : //Vector<Int> fieldsel=laSelection.asArrayInt("field");
1301 0 : Vector<Int> freqSpw;
1302 0 : Vector<Int> freqStart;
1303 0 : Vector<Int> freqNchan;
1304 0 : String newspw;
1305 : try{
1306 0 : MSUtil::getSpwInFreqRange(freqSpw, freqStart, freqNchan, elms, freqBeg(k), freqEnd(k),0.0, eltype, fieldsel[0]);
1307 0 : newspw=mergeSpwSel(freqSpw, freqStart, freqNchan, spwsel);
1308 : //cerr << "try " << freqSpw << " " << freqStart << " " << freqNchan << endl;
1309 : }
1310 0 : catch(...){
1311 : //cerr << "In catch " << endl;
1312 0 : newspw="";
1313 0 : }
1314 : //String newspw=mergeSpwSel(freqSpw, freqStart, freqNchan, spwsel);
1315 0 : if(newspw=="") newspw="-1";
1316 0 : msRec.define("spw", newspw);
1317 0 : partRec.defineRecord(String("ms"+String::toString(j)),msRec);
1318 0 : }
1319 :
1320 : }
1321 0 : retRec.defineRecord(String::toString(k), partRec);
1322 0 : }
1323 :
1324 :
1325 :
1326 :
1327 0 : return retRec;
1328 0 : }
1329 :
1330 :
1331 0 : String SynthesisUtilMethods::mergeSpwSel(const Vector<Int>& fspw, const Vector<Int>& fstart, const Vector<Int>& fnchan, const Matrix<Int>& spwsel)
1332 : {
1333 0 : String retval="";
1334 : Int cstart, cend;
1335 0 : for(Int k=0; k < fspw.shape()(0); ++k){
1336 0 : cstart=fstart(k);
1337 0 : cend=fstart(k)+fnchan(k)-1;
1338 0 : for (Int j=0; j < spwsel.shape()(0); ++j){
1339 : //need to put this here as multiple rows can have the same spw
1340 0 : cstart=fstart(k);
1341 0 : cend=fstart(k)+fnchan(k)-1;
1342 0 : if(spwsel(j,0)==fspw[k]){
1343 0 : if(cstart < spwsel(j,1)) cstart=spwsel(j,1);
1344 0 : if(cend > spwsel(j,2)) cend= spwsel(j,2);
1345 0 : if(!retval.empty()) retval=retval+(",");
1346 0 : retval=retval+String::toString(fspw[k])+":"+String::toString(cstart)+"~"+String::toString(cend);
1347 : }
1348 : }
1349 : }
1350 :
1351 :
1352 :
1353 0 : return retval;
1354 0 : }
1355 :
1356 : // Image cube partitioning rules for CUBE imaging
1357 0 : Record SynthesisUtilMethods::cubeImagePartition(Record &impars, Int npart)
1358 : {
1359 0 : LogIO os( LogOrigin("SynthesisUtilMethods","cubeImagePartition",WHERE) );
1360 :
1361 0 : Record onepart, allparts;
1362 :
1363 : // Duplicate the entire input record npart times, with a specific partition id.
1364 : // Modify each sub-record according to partition id.
1365 0 : for( Int part=0; part < npart; part++)
1366 : {
1367 :
1368 0 : onepart.assign(impars);
1369 :
1370 : //-------------------------------------------------
1371 : // WARNING : This is special-case code for two specific datasets
1372 0 : for ( uInt imfld=0; imfld<impars.nfields(); imfld++)
1373 : {
1374 0 : Record onefld = onepart.subRecord( RecordFieldId(String::toString(imfld)) );
1375 0 : Int nchan = onefld.asInt("nchan");
1376 : //String freqstart = onems.asString("freqstart");
1377 :
1378 0 : onefld.define("nchan", nchan/npart);
1379 0 : onefld.define("freqstart", (((Bool)part)?("1.2GHz"):("1.0GHz")) );
1380 :
1381 0 : String imname = onefld.asString("imagename");
1382 0 : onefld.define("imagename", imname+".n"+String::toString(part));
1383 :
1384 0 : onepart.defineRecord( RecordFieldId( String::toString(imfld) ), onefld );
1385 0 : }// end ms loop
1386 : //-------------------------------------------------
1387 :
1388 0 : allparts.defineRecord( RecordFieldId(String::toString(part)), onepart );
1389 :
1390 : }// end partition loop
1391 :
1392 0 : return allparts;
1393 :
1394 :
1395 0 : }
1396 :
1397 155 : String SynthesisUtilMethods::asComprehensibleDirectionString(MDirection const &direction)
1398 : {
1399 155 : MVAngle mvRa=direction.getAngle().getValue()(0);
1400 155 : MVAngle mvDec=direction.getAngle().getValue()(1);
1401 155 : ostringstream oos;
1402 155 : oos << " ";
1403 155 : Int widthRA=20;
1404 155 : Int widthDec=20;
1405 155 : oos.setf(ios::left, ios::adjustfield);
1406 155 : oos.width(widthRA); oos << mvRa(0.0).string(MVAngle::TIME,8);
1407 155 : oos.width(widthDec); oos << mvDec.string(MVAngle::DIG2,8);
1408 155 : oos << " "
1409 155 : << MDirection::showType(direction.getRefPtr()->getType());
1410 310 : return String(oos);
1411 155 : }
1412 :
1413 : /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1414 : /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1415 : ///////////////// Parameter Containers ///////////////////////////////////////////////////////
1416 : /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1417 : /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1418 :
1419 : // Read String from Record
1420 99647 : String SynthesisParams::readVal(const Record &rec, String id, String& val) const
1421 : {
1422 99647 : if( rec.isDefined( id ) )
1423 : {
1424 92160 : String inval("");
1425 92160 : if( rec.dataType( id )==TpString )
1426 92160 : { rec.get( id , inval ); // Read into temp string
1427 : // val = inval;
1428 : // return String("");
1429 : // Set value only if it is not a null string. Otherwise, leave it unchanged as it will
1430 : // retain the default value that was set before this function was called.
1431 92160 : if(inval.length()>0){val=inval;}
1432 92160 : return String("");
1433 : }
1434 0 : else { return String(id + " must be a string\n"); }
1435 92160 : }
1436 7487 : else { return String("");}
1437 : }
1438 :
1439 : // Read Integer from Record
1440 25380 : String SynthesisParams::readVal(const Record &rec, String id, Int& val) const
1441 : {
1442 25380 : if( rec.isDefined( id ) )
1443 : {
1444 25030 : if( rec.dataType( id )==TpInt ) { rec.get( id , val ); return String(""); }
1445 0 : else { return String(id + " must be an integer\n"); }
1446 : }
1447 350 : else { return String(""); }
1448 : }
1449 :
1450 : // Read Float from Record
1451 39441 : String SynthesisParams::readVal(const Record &rec, String id, Float& val) const
1452 : {
1453 39441 : if( rec.isDefined( id ) )
1454 : {
1455 36650 : if ( rec.dataType( id )==TpFloat || rec.dataType( id )==TpDouble )
1456 36650 : { rec.get( id , val ); return String(""); }
1457 0 : else { return String(id + " must be a float\n"); }
1458 : }
1459 2791 : else { return String(""); }
1460 : }
1461 :
1462 : // Read Bool from Record
1463 49350 : String SynthesisParams::readVal(const Record &rec, String id, Bool& val) const
1464 : {
1465 49350 : if( rec.isDefined( id ) )
1466 : {
1467 42056 : if( rec.dataType( id )==TpBool ) { rec.get( id , val ); return String(""); }
1468 0 : else { return String(id + " must be a bool\n"); }
1469 : }
1470 7294 : else{ return String(""); }
1471 : }
1472 :
1473 : // Read Vector<Int> from Record
1474 899 : String SynthesisParams::readVal(const Record &rec, String id, Vector<Int>& val) const
1475 : {
1476 899 : if( rec.isDefined( id ) )
1477 : {
1478 899 : if( rec.dataType( id )==TpArrayInt || rec.dataType( id )==TpArrayUInt )
1479 899 : { rec.get( id , val ); return String(""); }
1480 0 : else if ( rec.dataType( id ) == TpArrayBool ) // An empty python vector [] comes in as this.
1481 : {
1482 0 : Vector<Bool> vec; rec.get( id, vec );
1483 0 : if( vec.nelements()==0 ){val.resize(0); return String("");}
1484 0 : else{ return String(id + " must be a vector of strings.\n"); }
1485 0 : }
1486 0 : else { return String(id + " must be a vector of integers\n"); }
1487 : }
1488 0 : else{ return String(""); }
1489 : }
1490 :
1491 : // Read Vector<Float> from Record
1492 4363 : String SynthesisParams::readVal(const Record &rec, String id, Vector<Float>& val) const
1493 : {
1494 4363 : if( rec.isDefined( id ) )
1495 : {
1496 4363 : if( rec.dataType( id )==TpArrayFloat )
1497 : {
1498 2572 : rec.get( id , val ); return String("");
1499 : /*
1500 : Array<Float> vec; rec.get(id, vec );
1501 : cout << " vec : " << vec << endl;
1502 : if( vec.shape().nelements()==1 )
1503 : {
1504 : val.resize( vec.shape()[0] );
1505 : for(uInt i=0;i<val.nelements();i++){val[i]=(Float)vec(IPosition(1,i));}
1506 : return String("");
1507 : }
1508 : else { return String(id + " must be a 1D vector of floats"); }
1509 : */
1510 : }
1511 1791 : else if ( rec.dataType( id ) ==TpArrayDouble )
1512 : {
1513 170 : Vector<Double> vec; rec.get( id, vec );
1514 170 : val.resize(vec.nelements());
1515 510 : for(uInt i=0;i<val.nelements();i++){val[i]=(Float)vec[i];}
1516 170 : return String("");
1517 170 : }
1518 1621 : else if ( rec.dataType( id ) ==TpArrayInt )
1519 : {
1520 48 : Vector<Int> vec; rec.get( id, vec );
1521 48 : val.resize(vec.nelements());
1522 251 : for(uInt i=0;i<val.nelements();i++){val[i]=(Float)vec[i];}
1523 48 : return String("");
1524 48 : }
1525 1573 : else if ( rec.dataType( id ) == TpArrayBool ) // An empty python vector [] comes in as this.
1526 : {
1527 1573 : Vector<Bool> vec; rec.get( id, vec );
1528 1573 : if( vec.shape().product()==0 ){val.resize(0); return String("");}
1529 0 : else{ return String(id + " must be a vector of strings.\n"); }
1530 : // val.resize(0); return String("");
1531 1573 : }
1532 0 : else { return String(id + " must be a vector of floats\n"); }
1533 : }
1534 0 : else{ return String(""); }
1535 : }
1536 :
1537 : // Read Vector<String> from Record
1538 4107 : String SynthesisParams::readVal(const Record &rec, String id, Vector<String>& val) const
1539 : {
1540 4107 : if( rec.isDefined( id ) )
1541 : {
1542 4107 : if( rec.dataType( id )==TpArrayString || rec.dataType( id )==TpArrayChar )
1543 4104 : { rec.get( id , val ); return String(""); }
1544 3 : else if ( rec.dataType( id ) == TpArrayBool ) // An empty python vector [] comes in as this.
1545 : {
1546 3 : Vector<Bool> vec; rec.get( id, vec );
1547 3 : if( vec.nelements()==0 ){val.resize(0); return String("");}
1548 0 : else{ return String(id + " must be a vector of strings.\n"); }
1549 3 : }
1550 0 : else { return String(id + " must be a vector of strings.\n");
1551 : }
1552 : }
1553 0 : else{ return String(""); }
1554 : }
1555 :
1556 : // Convert String to Quantity
1557 11811 : String SynthesisParams::stringToQuantity(String instr, Quantity& qa) const
1558 : {
1559 : //QuantumHolder qh;
1560 : //String error;
1561 : // if( qh.fromString( error, instr ) ) { qa = qh.asQuantity(); return String(""); }
1562 : //else { return String("Error in converting " + instr + " to a Quantity : " + error + " \n"); }
1563 11811 : if ( casacore::Quantity::read( qa, instr ) ) { return String(""); }
1564 0 : else { return String("Error in converting " + instr + " to a Quantity \n"); }
1565 : }
1566 :
1567 : // Convert String to MDirection
1568 : // UR : TODO : If J2000 not specified, make it still work.
1569 2148 : String SynthesisParams::stringToMDirection(String instr, MDirection& md) const
1570 : {
1571 : try
1572 : {
1573 2148 : String tmpRF, tmpRA, tmpDEC;
1574 2148 : std::istringstream iss(instr);
1575 2148 : iss >> tmpRF >> tmpRA >> tmpDEC;
1576 2148 : if( tmpDEC.length() == 0 )// J2000 may not be specified.
1577 : {
1578 0 : tmpDEC = tmpRA;
1579 0 : tmpRA = tmpRF;
1580 0 : tmpRF = String("J2000");
1581 : }
1582 2148 : casacore::Quantity tmpQRA;
1583 2148 : casacore::Quantity tmpQDEC;
1584 2148 : casacore::Quantity::read(tmpQRA, tmpRA);
1585 2148 : casacore::Quantity::read(tmpQDEC, tmpDEC);
1586 :
1587 2148 : if(tmpQDEC.getFullUnit()==Unit("deg") && tmpDEC.contains(":")){
1588 0 : LogIO os( LogOrigin("SynthesisParams","stringToMDirection",WHERE) );
1589 : os << LogIO::WARN
1590 : << "You provided the Declination/Latitude value \""<< tmpDEC
1591 : << "\" which is understood to be in units of hours.\n"
1592 : << "If you meant degrees, please replace \":\" by \".\"."
1593 0 : << LogIO::POST;
1594 0 : }
1595 :
1596 : MDirection::Types theRF;
1597 2148 : Bool status = MDirection::getType(theRF, tmpRF);
1598 2148 : if (!status) {
1599 2 : throw AipsError();
1600 : }
1601 2146 : md = MDirection (tmpQRA, tmpQDEC, theRF);
1602 2146 : return String("");
1603 2158 : }
1604 2 : catch(AipsError &x)
1605 : {
1606 4 : return String("Error in converting '" + instr + "' to MDirection. Need format : 'J2000 19:59:28.500 +40.44.01.50'\n");
1607 2 : }
1608 : }
1609 :
1610 : // Read Quantity from a Record string
1611 9229 : String SynthesisParams::readVal(const Record &rec, String id, Quantity& val) const
1612 : {
1613 9229 : if( rec.isDefined( id ) )
1614 : {
1615 8283 : if( rec.dataType( id )==TpString )
1616 8283 : { String valstr; rec.get( id , valstr ); return stringToQuantity(valstr, val); }
1617 0 : else { return String(id + " must be a string in the format : '1.5GHz' or '0.2arcsec'...'\n"); }
1618 : }
1619 946 : else{ return String(""); }
1620 : }
1621 :
1622 : // Read MDirection from a Record string
1623 3094 : String SynthesisParams::readVal(const Record &rec, String id, MDirection& val) const
1624 : {
1625 3094 : if( rec.isDefined( id ) )
1626 : {
1627 2148 : if( rec.dataType( id )==TpString )
1628 2148 : { String valstr; rec.get( id , valstr ); return stringToMDirection(valstr, val); }
1629 0 : else { return String(id + " must be a string in the format : 'J2000 19:59:28.500 +40.44.01.50'\n"); }
1630 : }
1631 946 : else{ return String(""); }
1632 : }
1633 :
1634 : // Convert MDirection to String
1635 1798 : String SynthesisParams::MDirectionToString(MDirection val) const
1636 : {
1637 1798 : MVDirection mvpc( val.getAngle() );
1638 1798 : MVAngle ra = mvpc.get()(0);
1639 1798 : MVAngle dec = mvpc.get()(1);
1640 : // Beware of precision here......( for VLBA / ALMA ). 14 gives 8 digits after the decimal for arcsec.
1641 5394 : return String(val.getRefString() + " " + ra.string(MVAngle::TIME,14) + " " + dec.string(MVAngle::ANGLE,14));
1642 1798 : }
1643 :
1644 : // Convert Quantity to String
1645 6060 : String SynthesisParams::QuantityToString(Quantity val) const
1646 : {
1647 6060 : std::ostringstream ss;
1648 : //use digits10 to ensure the conersions involve use full decimal digits guranteed to be
1649 : //correct plus extra digits to deal with least significant digits (or replace with
1650 : // max_digits10 when it is available)
1651 6060 : ss.precision(std::numeric_limits<double>::digits10+2);
1652 6060 : ss << val;
1653 18180 : return ss.str();
1654 : // NOTE - 2017.10.04: It was found (CAS-10773) that we cannot use to_string for this as
1655 : // the decimal place is fixed to 6 digits.
1656 : //TT: change to C++11 to_string which handles double value to string conversion
1657 : //return String(std::to_string( val.getValue(val.getUnit()) )) + val.getUnit() ;
1658 6060 : }
1659 :
1660 : // Convert Record contains Quantity or Measure quantities to String
1661 49 : String SynthesisParams::recordQMToString(const Record &rec) const
1662 : {
1663 : Double val;
1664 49 : String unit;
1665 49 : if ( rec.isDefined("m0") )
1666 : {
1667 28 : Record subrec = rec.subRecord("m0");
1668 28 : subrec.get("value",val);
1669 28 : subrec.get("unit",unit);
1670 28 : }
1671 21 : else if (rec.isDefined("value") )
1672 : {
1673 21 : rec.get("value",val);
1674 21 : rec.get("unit",unit);
1675 : }
1676 147 : return String::toString(val) + unit;
1677 49 : }
1678 :
1679 :
1680 : /////////////////////// Selection Parameters
1681 :
1682 5105 : SynthesisParamsSelect::SynthesisParamsSelect():SynthesisParams()
1683 : {
1684 5105 : setDefaults();
1685 5105 : }
1686 :
1687 5115 : SynthesisParamsSelect::~SynthesisParamsSelect()
1688 : {
1689 5115 : }
1690 :
1691 11 : SynthesisParamsSelect::SynthesisParamsSelect(const SynthesisParamsSelect& other){
1692 11 : operator=(other);
1693 11 : }
1694 :
1695 2035 : SynthesisParamsSelect& SynthesisParamsSelect::operator=(const SynthesisParamsSelect& other){
1696 2035 : if(this!=&other) {
1697 2035 : msname=other.msname;
1698 2035 : spw=other.spw;
1699 2035 : freqbeg=other.freqbeg;
1700 2035 : freqend=other.freqend;
1701 2035 : freqframe=other.freqframe;
1702 2035 : field=other.field;
1703 2035 : antenna=other.antenna;
1704 2035 : timestr=other.timestr;
1705 2035 : scan=other.scan;
1706 2035 : obs=other.obs;
1707 2035 : state=other.state;
1708 2035 : uvdist=other.uvdist;
1709 2035 : taql=other.taql;
1710 2035 : usescratch=other.usescratch;
1711 2035 : readonly=other.readonly;
1712 2035 : incrmodel=other.incrmodel;
1713 2035 : datacolumn=other.datacolumn;
1714 :
1715 : }
1716 2035 : return *this;
1717 : }
1718 :
1719 3081 : void SynthesisParamsSelect::fromRecord(const Record &inrec)
1720 : {
1721 3081 : setDefaults();
1722 :
1723 3081 : String err("");
1724 :
1725 : try
1726 : {
1727 :
1728 3081 : err += readVal( inrec, String("msname"), msname );
1729 :
1730 3081 : err += readVal( inrec, String("readonly"), readonly );
1731 3081 : err += readVal( inrec, String("usescratch"), usescratch );
1732 :
1733 : // override with entries from savemodel.
1734 3081 : String savemodel("");
1735 3081 : err += readVal( inrec, String("savemodel"), savemodel );
1736 3081 : if( savemodel=="none" ){usescratch=false; readonly=true;}
1737 1959 : else if( savemodel=="virtual" ){usescratch=false; readonly=false;}
1738 1942 : else if ( savemodel=="modelcolumn" ){ usescratch=true; readonly=false; }
1739 :
1740 3081 : err += readVal( inrec, String("incrmodel"), incrmodel );
1741 :
1742 3081 : err += readVal( inrec, String("spw"), spw );
1743 :
1744 : /// -------------------------------------------------------------------------------------
1745 : // Why are these params here ? Repeats of defineimage.
1746 3081 : err += readVal( inrec, String("freqbeg"), freqbeg);
1747 3081 : err += readVal( inrec, String("freqend"), freqend);
1748 :
1749 3081 : String freqframestr( MFrequency::showType(freqframe) );
1750 3081 : err += readVal( inrec, String("outframe"), freqframestr);
1751 3081 : if( ! MFrequency::getType(freqframe, freqframestr) )
1752 0 : { err += "Invalid Frequency Frame " + freqframestr ; }
1753 : /// -------------------------------------------------------------------------------------
1754 :
1755 3081 : err += readVal( inrec, String("field"),field);
1756 3081 : err += readVal( inrec, String("antenna"),antenna);
1757 3081 : err += readVal( inrec, String("timestr"),timestr);
1758 3081 : err += readVal( inrec, String("scan"),scan);
1759 3081 : err += readVal( inrec, String("obs"),obs);
1760 3081 : err += readVal( inrec, String("state"),state);
1761 3081 : err += readVal( inrec, String("uvdist"),uvdist);
1762 3081 : err += readVal( inrec, String("taql"),taql);
1763 :
1764 3081 : err += readVal( inrec, String("datacolumn"),datacolumn);
1765 :
1766 3081 : err += verify();
1767 :
1768 3081 : }
1769 0 : catch(AipsError &x)
1770 : {
1771 0 : err = err + x.getMesg() + "\n";
1772 0 : }
1773 :
1774 3081 : if( err.length()>0 ) throw(AipsError("Invalid Selection Parameter set : " + err));
1775 :
1776 3081 : }
1777 :
1778 3081 : String SynthesisParamsSelect::verify() const
1779 : {
1780 3081 : String err;
1781 : // Does the MS exist on disk.
1782 3081 : Directory thems( msname );
1783 3081 : if( thems.exists() )
1784 : {
1785 : // Is it readable ?
1786 3081 : if( ! thems.isReadable() )
1787 0 : { err += "MS " + msname + " is not readable.\n"; }
1788 : // Depending on 'readonly', is the MS writable ?
1789 3081 : if( readonly==false && ! thems.isWritable() )
1790 0 : { err += "MS " + msname + " is not writable.\n"; }
1791 : }
1792 : else
1793 0 : { err += "MS does not exist : " + msname + "\n"; }
1794 :
1795 6162 : return err;
1796 3081 : }
1797 :
1798 8186 : void SynthesisParamsSelect::setDefaults()
1799 : {
1800 8186 : msname="";
1801 8186 : spw="";
1802 8186 : freqbeg="";
1803 8186 : freqend="";
1804 8186 : MFrequency::getType(freqframe,"LSRK");
1805 8186 : field="";
1806 8186 : antenna="";
1807 8186 : timestr="";
1808 8186 : scan="";
1809 8186 : obs="";
1810 8186 : state="";
1811 8186 : uvdist="";
1812 8186 : taql="";
1813 8186 : usescratch=false;
1814 8186 : readonly=true;
1815 8186 : incrmodel=false;
1816 8186 : datacolumn="corrected";
1817 8186 : }
1818 :
1819 2083 : Record SynthesisParamsSelect::toRecord()const
1820 : {
1821 2083 : Record selpar;
1822 2083 : selpar.define("msname",msname);
1823 2083 : selpar.define("spw",spw);
1824 2083 : selpar.define("freqbeg",freqbeg);
1825 2083 : selpar.define("freqend",freqend);
1826 2083 : selpar.define("freqframe", MFrequency::showType(freqframe)); // Convert MFrequency::Types to String
1827 : //looks like fromRecord looks for outframe !
1828 2083 : selpar.define("outframe", MFrequency::showType(freqframe));
1829 2083 : selpar.define("field",field);
1830 2083 : selpar.define("antenna",antenna);
1831 2083 : selpar.define("timestr",timestr);
1832 2083 : selpar.define("scan",scan);
1833 2083 : selpar.define("obs",obs);
1834 2083 : selpar.define("state",state);
1835 2083 : selpar.define("uvdist",uvdist);
1836 2083 : selpar.define("taql",taql);
1837 2083 : selpar.define("usescratch",usescratch);
1838 2083 : selpar.define("readonly",readonly);
1839 2083 : selpar.define("incrmodel",incrmodel);
1840 2083 : selpar.define("datacolumn",datacolumn);
1841 :
1842 2083 : return selpar;
1843 0 : }
1844 :
1845 :
1846 : /////////////////////// Image Parameters
1847 :
1848 5545 : SynthesisParamsImage::SynthesisParamsImage():SynthesisParams()
1849 : {
1850 5545 : setDefaults();
1851 5545 : }
1852 :
1853 5544 : SynthesisParamsImage::~SynthesisParamsImage()
1854 : {
1855 5544 : }
1856 :
1857 3715 : SynthesisParamsImage& SynthesisParamsImage::operator=(const SynthesisParamsImage& other){
1858 3715 : if(this != &other){
1859 3715 : imageName=other.imageName;
1860 3715 : stokes=other.stokes;
1861 3715 : startModel.resize(); startModel=other.startModel;
1862 3715 : imsize.resize(); imsize=other.imsize;
1863 3715 : cellsize.resize(); cellsize=other.cellsize;
1864 3715 : projection=other.projection;
1865 3715 : useNCP=other.useNCP;
1866 3715 : phaseCenter=other.phaseCenter;
1867 3715 : phaseCenterFieldId=other.phaseCenterFieldId;
1868 3715 : obslocation=other.obslocation;
1869 3715 : pseudoi=other.pseudoi;
1870 3715 : nchan=other.nchan;
1871 3715 : nTaylorTerms=other.nTaylorTerms;
1872 3715 : chanStart=other.chanStart;
1873 3715 : chanStep=other.chanStep;
1874 3715 : freqStart=other.freqStart;
1875 3715 : freqStep=other.freqStep;
1876 3715 : refFreq=other.refFreq;
1877 3715 : velStart=other.velStart;
1878 3715 : velStep=other.velStep;
1879 3715 : freqFrame=other.freqFrame;
1880 3715 : mFreqStart=other.mFreqStart;
1881 3715 : mFreqStep=other.mFreqStep;
1882 3715 : mVelStart=other.mVelStart;
1883 3715 : mVelStep=other.mVelStep;
1884 3715 : restFreq.resize(); restFreq=other.restFreq;
1885 3715 : start=other.start;
1886 3715 : step=other.step;
1887 3715 : frame=other.frame;
1888 3715 : veltype=other.veltype;
1889 3715 : mode=other.mode;
1890 3715 : reffreq=other.reffreq;
1891 3715 : sysvel=other.sysvel;
1892 3715 : sysvelframe=other.sysvelframe;
1893 3715 : sysvelvalue=other.sysvelvalue;
1894 3715 : qmframe=other.qmframe;
1895 3715 : mveltype=other.mveltype;
1896 3715 : tststr=other.tststr;
1897 3715 : startRecord=other.startRecord;
1898 3715 : stepRecord=other.stepRecord;
1899 3715 : reffreqRecord=other.reffreqRecord;
1900 3715 : sysvelRecord=other.sysvelRecord;
1901 3715 : restfreqRecord=other.restfreqRecord;
1902 3715 : csysRecord=other.csysRecord;
1903 3715 : csys=other.csys;
1904 3715 : imshape.resize(); imshape=other.imshape;
1905 3715 : freqFrameValid=other.freqFrameValid;
1906 3715 : overwrite=other.overwrite;
1907 3715 : deconvolver=other.deconvolver;
1908 3715 : distance=other.distance;
1909 3715 : trackDir=other.trackDir;
1910 3715 : trackSource=other.trackSource;
1911 3715 : movingSource=other.movingSource;
1912 :
1913 :
1914 :
1915 : }
1916 :
1917 3715 : return *this;
1918 :
1919 : }
1920 :
1921 1685 : void SynthesisParamsImage::fromRecord(const casacore::Record &inrec) {
1922 1685 : fromRecord(inrec, False);
1923 1684 : }
1924 :
1925 1845 : void SynthesisParamsImage::fromRecord(const casacore::Record &inrec,
1926 : const casacore::Bool isSingleDish) {
1927 1845 : setDefaults();
1928 1845 : String err("");
1929 3690 : LogIO os(LogOrigin("SynthesisParamsImage", "fromRecord"));
1930 :
1931 : try {
1932 1845 : err += readVal(inrec, String("imagename"), imageName);
1933 :
1934 : //// imsize
1935 1845 : if (inrec.isDefined("imsize")) {
1936 1845 : DataType tp = inrec.dataType("imsize");
1937 1845 : if (tp == TpInt) { // A single integer for both dimensions.
1938 : Int npix;
1939 742 : inrec.get("imsize", npix);
1940 742 : imsize.resize(2);
1941 742 : imsize.set(npix);
1942 1103 : } else if (tp == TpArrayInt) { // An integer array : [ nx ] or [ nx, ny ]
1943 1103 : Vector<Int> ims;
1944 1103 : inrec.get("imsize", ims);
1945 1103 : if (ims.nelements() == 1) { // [ nx ]
1946 45 : imsize.set(ims[0]);
1947 1058 : } else if (ims.nelements() == 2) { // [ nx, ny ]
1948 1058 : imsize[0] = ims[0];
1949 1058 : imsize[1] = ims[1];
1950 : } else { // [ nx, ny ]
1951 0 : err += "imsize must be either a single integer, or a vector of two integers\n";
1952 : }
1953 1103 : } else { // Wrong data type
1954 0 : err += "imsize must be either a single integer, or a vector of two integers\n";
1955 : }
1956 : } //imsize
1957 :
1958 : //// cellsize
1959 1845 : if (inrec.isDefined("cell")) {
1960 : try {
1961 1845 : DataType tp = inrec.dataType("cell");
1962 1845 : if (tp == TpInt ||
1963 1845 : tp == TpFloat ||
1964 : tp == TpDouble) {
1965 11 : Double cell = inrec.asDouble("cell");
1966 11 : cellsize.set(Quantity(cell, "arcsec"));
1967 1845 : } else if (tp == TpArrayInt ||
1968 1834 : tp == TpArrayFloat ||
1969 : tp == TpArrayDouble) {
1970 1 : Vector<Double> cells;
1971 1 : inrec.get("cell", cells);
1972 1 : if (cells.nelements() == 1) { // [ cellx ]
1973 0 : cellsize.set(Quantity(cells[0], "arcsec"));
1974 1 : } else if (cells.nelements() == 2) { // [ cellx, celly ]
1975 1 : cellsize[0] = Quantity(cells[0], "arcsec");
1976 1 : cellsize[1] = Quantity(cells[1], "arcsec");
1977 : } else { // Wrong array length
1978 0 : err += "cellsize must be a single integer/string, or a vector of two integers/strings\n";
1979 : }
1980 1834 : } else if (tp == TpString) {
1981 833 : String cell;
1982 833 : inrec.get("cell", cell);
1983 833 : Quantity qcell;
1984 833 : err += stringToQuantity(cell, qcell);
1985 833 : cellsize.set(qcell);
1986 1833 : } else if (tp == TpArrayString) {
1987 1000 : Array<String> cells;
1988 1000 : inrec.get("cell", cells);
1989 1000 : Vector<String> vcells(cells);
1990 1000 : if (cells.nelements() == 1) { // [ cellx ]
1991 12 : Quantity qcell;
1992 12 : err += stringToQuantity(vcells[0], qcell);
1993 12 : cellsize.set(qcell);
1994 1000 : } else if (cells.nelements() == 2) { // [ cellx, celly ]
1995 988 : err += stringToQuantity(vcells[0], cellsize[0]);
1996 988 : err += stringToQuantity(vcells[1], cellsize[1]);
1997 : } else { // Wrong array length
1998 0 : err += "cellsize must be a single integer/string, or a vector of two integers/strings\n";
1999 : }
2000 1000 : } else { // Wrong data type
2001 0 : err += "cellsize must be a single integer/string, or a vector of two integers/strings\n";
2002 : }
2003 0 : } catch (AipsError &x) {
2004 0 : err += "Error reading cellsize : " + x.getMesg();
2005 0 : }
2006 : } // cellsize
2007 :
2008 : //// stokes
2009 1845 : err += readVal(inrec, String("stokes"), stokes);
2010 1845 : if (stokes.matches("pseudoI")) {
2011 1 : stokes = "I";
2012 1 : pseudoi = true;
2013 : } else {
2014 1844 : pseudoi = false;
2015 : }
2016 :
2017 : /// PseudoI
2018 :
2019 : ////nchan
2020 1845 : err += readVal(inrec, String("nchan"), nchan);
2021 :
2022 : /// phaseCenter (as a string) . // Add INT support later.
2023 : //err += readVal( inrec, String("phasecenter"), phaseCenter );
2024 1845 : if (inrec.isDefined("phasecenter")) {
2025 1845 : String pcent("");
2026 1845 : if (inrec.dataType("phasecenter") == TpString) {
2027 1819 : inrec.get("phasecenter", pcent);
2028 1819 : if (pcent.length() > 0) { // if it's zero length, it means 'figure out from first field in MS'.
2029 1249 : err += readVal(inrec, String("phasecenter"), phaseCenter);
2030 1249 : phaseCenterFieldId = -1;
2031 : //// Phase Center Field ID.... if explicitly specified, and not via phasecenter.
2032 : // Need this, to deal with a null phase center being translated to a string to go back out.
2033 1249 : err += readVal(inrec, String("phasecenterfieldid"), phaseCenterFieldId);
2034 : } else {
2035 570 : phaseCenterFieldId = -2; // deal with this later in buildCoordinateSystem to assign the first selected field
2036 : }
2037 : }
2038 1845 : if (inrec.dataType("phasecenter") == TpInt ||
2039 5509 : inrec.dataType("phasecenter") == TpFloat ||
2040 3664 : inrec.dataType("phasecenter") == TpDouble) {
2041 : // This will override the previous setting to 0 if the phaseCenter string is zero length.
2042 26 : err += readVal(inrec, String("phasecenter"), phaseCenterFieldId);
2043 : }
2044 1871 : if ((inrec.dataType("phasecenter") != TpString && inrec.dataType("phasecenter") != TpInt
2045 1871 : && inrec.dataType("phasecenter") != TpFloat && inrec.dataType("phasecenter") != TpDouble)) {
2046 0 : err += String("Cannot set phasecenter. Please specify a string or int\n");
2047 : }
2048 1845 : }
2049 :
2050 : //// Projection
2051 1845 : if (inrec.isDefined("projection")) {
2052 1845 : if (inrec.dataType("projection") == TpString) {
2053 1845 : String pstr;
2054 1845 : inrec.get("projection", pstr);
2055 : try {
2056 1845 : if (pstr.matches("NCP")) {
2057 1 : pstr = "SIN";
2058 1 : useNCP = true;
2059 : }
2060 1845 : projection = Projection::type(pstr);
2061 0 : } catch (AipsError &x) {
2062 0 : err += String("Invalid projection code : " + pstr);
2063 0 : }
2064 1845 : } else {
2065 0 : err += "projection must be a string\n";
2066 : }
2067 : } //projection
2068 :
2069 : // Frequency frame stuff.
2070 1845 : err += readVal(inrec, String("specmode"), mode);
2071 : // Alias for 'mfs' is 'cont'
2072 1845 : if (mode == "cont") mode = "mfs";
2073 :
2074 1845 : err += readVal(inrec, String("outframe"), frame);
2075 1845 : qmframe = "";
2076 : // mveltype is only set when start/step is given in mdoppler
2077 1845 : mveltype = "";
2078 : //start
2079 1845 : String startType("");
2080 1845 : String widthType("");
2081 1845 : if (inrec.isDefined("start")) {
2082 1845 : if (inrec.dataType("start") == TpInt) {
2083 239 : err += readVal(inrec, String("start"), chanStart);
2084 239 : start = String::toString(chanStart);
2085 239 : startType = "chan";
2086 1606 : } else if (inrec.dataType("start") == TpString) {
2087 1571 : err += readVal(inrec, String("start"), start);
2088 1571 : if (start.contains("Hz")) {
2089 157 : stringToQuantity(start, freqStart);
2090 157 : startType = "freq";
2091 1414 : } else if (start.contains("m/s")) {
2092 46 : stringToQuantity(start, velStart);
2093 46 : startType = "vel";
2094 : }
2095 35 : } else if (inrec.dataType("start") == TpRecord) {
2096 : //record can be freq in Quantity or MFreaquency or vel in Quantity or
2097 : //MRadialVelocity or Doppler (by me.todoppler())
2098 : // ** doppler => converted to radialvel with frame
2099 35 : startRecord = inrec.subRecord("start");
2100 35 : if (startRecord.isDefined("m0")) {
2101 : //must be a measure
2102 21 : String mtype;
2103 21 : startRecord.get("type", mtype);
2104 21 : if (mtype == "frequency") {
2105 : //mfrequency
2106 7 : startRecord.get(String("refer"), qmframe);
2107 7 : if (frame != "" && frame != qmframe) {
2108 : // should emit warning to the logger
2109 0 : cerr << "The frame in start:" << qmframe << " Override frame=" << frame << endl;
2110 : }
2111 7 : start = recordQMToString(startRecord);
2112 7 : stringToQuantity(start, freqStart);
2113 7 : startType = "freq";
2114 14 : } else if (mtype == "radialvelocity") {
2115 : //mradialvelocity
2116 7 : startRecord.get(String("refer"), qmframe);
2117 7 : if (frame != "" && frame != qmframe) {
2118 : // should emit warning to the logger
2119 7 : cerr << "The frame in start:" << qmframe << " Override frame=" << frame << endl;
2120 : }
2121 7 : start = recordQMToString(startRecord);
2122 7 : stringToQuantity(start, velStart);
2123 7 : startType = "vel";
2124 7 : } else if (mtype == "doppler") {
2125 : //use veltype in mdoppler
2126 : //start = MDopToVelString(startRecord);
2127 7 : start = recordQMToString(startRecord);
2128 7 : stringToQuantity(start, velStart);
2129 7 : startRecord.get(String("refer"), mveltype);
2130 7 : mveltype.downcase();
2131 7 : startType = "vel";
2132 : }
2133 21 : } else {
2134 14 : start = recordQMToString(startRecord);
2135 14 : if (start.contains("Hz")) {
2136 7 : stringToQuantity(start, freqStart);
2137 7 : startType = "freq";
2138 7 : } else if (start.contains("m/s")) {
2139 7 : stringToQuantity(start, velStart);
2140 7 : startType = "vel";
2141 : } else {
2142 0 : err += String("Unrecognized Quantity unit for start, must contain m/s or Hz\n");
2143 : }
2144 : }
2145 : } else {
2146 0 : err += String("start must be an integer, a string, or frequency/velocity in Quantity/Measure\n");
2147 : }
2148 : }
2149 :
2150 : //step
2151 1845 : if (inrec.isDefined("width")) {
2152 1845 : if (inrec.dataType("width") == TpInt) {
2153 206 : err += readVal(inrec, String("width"), chanStep);
2154 206 : step = String::toString(chanStep);
2155 206 : widthType = "chan";
2156 1639 : } else if (inrec.dataType("width") == TpString) {
2157 1625 : err += readVal(inrec, String("width"), step);
2158 1625 : if (step.contains("Hz")) {
2159 142 : stringToQuantity(step, freqStep);
2160 142 : widthType = "freq";
2161 1483 : } else if (step.contains("m/s")) {
2162 50 : stringToQuantity(step, velStep);
2163 50 : widthType = "vel";
2164 : }
2165 14 : } else if (inrec.dataType("width") == TpRecord) {
2166 : //record can be freq in Quantity or MFreaquency or vel in Quantity or
2167 : //MRadialVelocity or Doppler (by me.todoppler())
2168 : // ** doppler => converted to radialvel with frame
2169 14 : stepRecord = inrec.subRecord("width");
2170 14 : if (stepRecord.isDefined("m0")) {
2171 : //must be a measure
2172 7 : String mtype;
2173 7 : stepRecord.get("type", mtype);
2174 7 : if (mtype == "frequency") {
2175 : //mfrequency
2176 0 : stepRecord.get(String("refer"), qmframe);
2177 0 : if (frame != "" && frame != qmframe) {
2178 : // should emit warning to the logger
2179 0 : cerr << "The frame in step:" << qmframe << " Override frame=" << frame << endl;
2180 : }
2181 0 : step = recordQMToString(stepRecord);
2182 0 : stringToQuantity(step, freqStep);
2183 0 : widthType = "freq";
2184 7 : } else if (mtype == "radialvelocity") {
2185 : //mradialvelocity
2186 7 : stepRecord.get(String("refer"), qmframe);
2187 7 : if (frame != "" && frame != qmframe) {
2188 : // should emit warning to the logger
2189 0 : cerr << "The frame in step:" << qmframe << " Override frame=" << frame << endl;
2190 : }
2191 7 : step = recordQMToString(stepRecord);
2192 7 : stringToQuantity(step, velStep);
2193 7 : widthType = "vel";
2194 0 : } else if (mtype == "doppler") {
2195 : //step = MDopToVelString(stepRecord);
2196 0 : step = recordQMToString(stepRecord);
2197 0 : stringToQuantity(step, velStep);
2198 0 : startRecord.get(String("refer"), mveltype);
2199 0 : mveltype.downcase();
2200 0 : widthType = "vel";
2201 : }
2202 7 : } else {
2203 7 : step = recordQMToString(stepRecord);
2204 7 : if (step.contains("Hz")) {
2205 0 : stringToQuantity(step, freqStep);
2206 0 : widthType = "freq";
2207 7 : } else if (step.contains("m/s")) {
2208 7 : stringToQuantity(step, velStep);
2209 7 : widthType = "vel";
2210 : } else {
2211 0 : err += String("Unrecognized Quantity unit for step, must contain m/s or Hz\n");
2212 : }
2213 : }
2214 : } else {
2215 0 : err += String("step must be an integer, a string, or frequency/velocity in Quantity/Measure\n");
2216 : }
2217 : }
2218 :
2219 : //check for start, width unit consistentcy
2220 1845 : if (startType != widthType && startType != "" && widthType != "") {
2221 0 : err += String("Cannot mix start and width with different unit types (e.g. km/s vs. Hz)\n");
2222 : }
2223 :
2224 : //reffreq (String, Quantity, or Measure)
2225 1845 : if (inrec.isDefined("reffreq")) {
2226 1845 : if (inrec.dataType("reffreq") == TpString) {
2227 1845 : err += readVal(inrec, String("reffreq"), refFreq);
2228 0 : } else if (inrec.dataType("reffreq") == TpRecord) {
2229 0 : String reffreqstr;
2230 0 : reffreqRecord = inrec.subRecord("reffreq");
2231 0 : if (reffreqRecord.isDefined("m0")) {
2232 0 : String mtype;
2233 0 : reffreqRecord.get("type", mtype);
2234 0 : if (mtype == "frequency") {
2235 0 : reffreqstr = recordQMToString(reffreqRecord);
2236 0 : stringToQuantity(reffreqstr, refFreq);
2237 : } else {
2238 0 : err += String("Unrecognized Measure for reffreq, must be a frequency measure\n");
2239 : }
2240 0 : } else {
2241 0 : reffreqstr = recordQMToString(reffreqRecord);
2242 0 : if (reffreqstr.contains("Hz")) {
2243 0 : stringToQuantity(reffreqstr, refFreq);
2244 : } else {
2245 0 : err += String("Unrecognized Quantity unit for reffreq, must contain Hz\n");
2246 : }
2247 : }
2248 0 : } else {
2249 0 : err += String("reffreq must be a string, or frequency in Quantity/Measure\n");
2250 : }
2251 : }
2252 :
2253 1845 : err += readVal(inrec, String("veltype"), veltype);
2254 1845 : veltype = mveltype != "" ? mveltype : veltype;
2255 : // sysvel (String, Quantity)
2256 1845 : if (inrec.isDefined("sysvel")) {
2257 1845 : if (inrec.dataType("sysvel") == TpString) {
2258 1845 : err += readVal(inrec, String("sysvel"), sysvel);
2259 0 : } else if (inrec.dataType("sysvel") == TpRecord) {
2260 0 : sysvelRecord = inrec.subRecord("sysvel");
2261 0 : sysvel = recordQMToString(sysvelRecord);
2262 0 : if (sysvel == "" || !sysvel.contains("m/s")) {
2263 0 : err += String("Unrecognized Quantity unit for sysvel, must contain m/s\n");
2264 : }
2265 : } else {
2266 0 : err += String("sysvel must be a string, or velocity in Quantity\n");
2267 : }
2268 : }
2269 1845 : err += readVal(inrec, String("sysvelframe"), sysvelframe);
2270 :
2271 : // rest frequencies (record or vector of Strings)
2272 1845 : if (inrec.isDefined("restfreq")) {
2273 1845 : Vector<String> rfreqs(0);
2274 1845 : Record restfreqSubRecord;
2275 1845 : if (inrec.dataType("restfreq") == TpRecord) {
2276 0 : restfreqRecord = inrec.subRecord("restfreq");
2277 : // assume multiple restfreqs are index as '0','1'..
2278 0 : if (restfreqRecord.isDefined("0")) {
2279 0 : rfreqs.resize(restfreqRecord.nfields());
2280 0 : for (uInt fr = 0; fr < restfreqRecord.nfields(); fr++) {
2281 0 : restfreqSubRecord = restfreqRecord.subRecord(String::toString(fr));
2282 0 : rfreqs[fr] = recordQMToString(restfreqSubRecord);
2283 : }
2284 : }
2285 1845 : } else if (inrec.dataType("restfreq") == TpArrayString) {
2286 967 : err += readVal(inrec, String("restfreq"), rfreqs);
2287 878 : } else if (inrec.dataType("restfreq") == TpString) {
2288 8 : rfreqs.resize(1);
2289 8 : err += readVal(inrec, String("restfreq"), rfreqs[0]);
2290 : }
2291 1845 : restFreq.resize(rfreqs.nelements());
2292 2108 : for (uInt fr = 0; fr < rfreqs.nelements(); fr++) {
2293 263 : err += stringToQuantity(rfreqs[fr], restFreq[fr]);
2294 : }
2295 1845 : } // if def restfreq
2296 :
2297 : // optional - coordsys, imshape
2298 : // if exist use them. May need a consistency check with the rest of impars?
2299 1845 : if (inrec.isDefined("csys")) {
2300 : // cout<<"HAS CSYS KEY - got from input record"<<endl;
2301 899 : if (inrec.dataType("csys") == TpRecord) {
2302 : //csysRecord = inrec.subRecord("csys");
2303 899 : csysRecord.defineRecord("coordsys", inrec.subRecord("csys"));
2304 : }
2305 899 : if (inrec.isDefined("imshape")) {
2306 899 : if (inrec.dataType("imshape") == TpArrayInt) {
2307 899 : err += readVal(inrec, String("imshape"), imshape);
2308 : }
2309 : }
2310 : }
2311 :
2312 : //String freqframestr( MFrequency::showType(freqFrame) );
2313 : //err += readVal( inrec, String("outframe"), freqframestr);
2314 : //if( ! MFrequency::getType(freqFrame, freqframestr) )
2315 : // { err += "Invalid Frequency Frame " + freqframestr ; }
2316 :
2317 1845 : String freqframestr = (frame != "" && qmframe != "") ? qmframe : frame;
2318 1845 : if (frame != "" && !MFrequency::getType(freqFrame, freqframestr)) {
2319 1 : err += "Invalid Frequency Frame " + freqframestr;
2320 : }
2321 1845 : err += readVal(inrec, String("restart"), overwrite);
2322 :
2323 1845 : err += readVal(inrec, String("freqframevalid"), freqFrameValid);
2324 : // startmodel parsing copied in SynthesisParamDeconv. Clean this up !!!
2325 1845 : if (inrec.isDefined("startmodel")) {
2326 1845 : if (inrec.dataType("startmodel") == TpString) {
2327 939 : String onemodel;
2328 939 : err += readVal(inrec, String("startmodel"), onemodel);
2329 939 : if (onemodel.length() > 0) {
2330 16 : startModel.resize(1);
2331 16 : startModel[0] = onemodel;
2332 : } else {
2333 923 : startModel.resize();
2334 : }
2335 2752 : } else if (inrec.dataType("startmodel") == TpArrayString ||
2336 907 : inrec.dataType("startmodel") == TpArrayBool) {
2337 906 : err += readVal(inrec, String("startmodel"), startModel);
2338 : } else {
2339 0 : err += String("startmodel must be either a string(singleterm) or a list of strings(multiterm)\n");
2340 : }
2341 : }
2342 :
2343 1845 : err += readVal(inrec, String("nterms"), nTaylorTerms);
2344 1845 : err += readVal(inrec, String("deconvolver"), deconvolver);
2345 :
2346 : // Force nchan=1 for anything other than cube modes...
2347 1845 : if (mode == "mfs") nchan = 1;
2348 : //read obslocation
2349 1845 : if (inrec.isDefined("obslocation_rec")) {
2350 899 : String errorobs;
2351 899 : const Record obsrec = inrec.asRecord("obslocation_rec");
2352 899 : MeasureHolder mh;
2353 899 : if (!mh.fromRecord(errorobs, obsrec)) {
2354 0 : err += errorobs;
2355 : }
2356 899 : obslocation = mh.asMPosition();
2357 899 : }
2358 1845 : err += verify(isSingleDish);
2359 1845 : }
2360 0 : catch (AipsError &x) {
2361 0 : err = err + x.getMesg() + "\n";
2362 0 : }
2363 :
2364 1845 : if (err.length() > 0) throw(AipsError("Invalid Image Parameter set : " + err));
2365 1849 : }
2366 :
2367 0 : String SynthesisParamsImage::MDopToVelString(Record &rec)
2368 : {
2369 0 : if( rec.isDefined("type") ) {
2370 0 : String measType;
2371 0 : String unit;
2372 0 : Double val = 0;
2373 0 : rec.get("type", measType);
2374 0 : if(measType=="doppler") {
2375 0 : rec.get(String("refer"), mveltype);
2376 0 : Record dopRecord = rec.subRecord("m0");
2377 0 : String dopstr = recordQMToString(dopRecord);
2378 : //cerr<<"dopstr="<<dopstr<<endl;
2379 : MRadialVelocity::Types mvType;
2380 : //use input frame
2381 0 : qmframe = frame!=""? frame: "LSRK";
2382 0 : MRadialVelocity::getType(mvType, qmframe);
2383 : MDoppler::Types mdType;
2384 0 : MDoppler::getType(mdType, mveltype);
2385 0 : MDoppler dop(Quantity(val,unit), mdType);
2386 0 : MRadialVelocity mRadVel(MRadialVelocity::fromDoppler(dop, mvType));
2387 0 : Double velval = mRadVel.get("m/s").getValue();
2388 0 : return start = String::toString(velval) + String("m/s");
2389 0 : }
2390 0 : else { return String("");}
2391 0 : }
2392 0 : else { return String("");}
2393 : }
2394 :
2395 0 : String SynthesisParamsImage::verify() const
2396 : {
2397 0 : verify(False);
2398 0 : }
2399 :
2400 1845 : String SynthesisParamsImage::verify(const casacore::Bool isSingleDish) const
2401 : {
2402 1845 : LogIO os;
2403 1845 : String err;
2404 :
2405 1845 : if(imageName=="") {err += "Please supply an image name\n";}
2406 :
2407 1845 : if(imsize.nelements() != 2){err += "imsize must be a vector of 2 Ints\n";}
2408 1845 : if(cellsize.nelements() != 2) {err += "cellsize must be a vector of 2 Quantities\n";}
2409 1845 : if(cellsize[0].getValue() == 0.0 || cellsize[1].getValue() == 0.0){
2410 1 : err += "cellsize must be nonzero\n";
2411 : }
2412 :
2413 : //// default is nt=2 but deconvolver != mtmfs by default.
2414 : // if( nchan>1 and nTaylorTerms>1 )
2415 : // {err += "Cannot have more than one channel with ntaylorterms>1\n";}
2416 :
2417 1845 : if((mode=="mfs") && nchan > 1){
2418 0 : err += "specmode=mfs cannot have nchan="+String::toString(nchan)+" (must be 1)\n";
2419 : }
2420 :
2421 2071 : if(! stokes.matches("I") && ! stokes.matches("Q") &&
2422 215 : ! stokes.matches("U") && ! stokes.matches("V") &&
2423 153 : ! stokes.matches("RR") && ! stokes.matches("LL") &&
2424 153 : ! stokes.matches("XX") && ! stokes.matches("YY") &&
2425 151 : ! stokes.matches("IV") && ! stokes.matches("IQ") &&
2426 140 : ! stokes.matches("RRLL") && ! stokes.matches("XXYY") &&
2427 138 : ! stokes.matches("QU") && ! stokes.matches("UV") &&
2428 2199 : ! stokes.matches("IQU") && ! stokes.matches("IUV") &&
2429 128 : ! stokes.matches("IQUV")){
2430 :
2431 0 : err += "Stokes " + stokes + " is an unsupported option \n";
2432 : }
2433 :
2434 : /// err += verifySpectralSetup();
2435 :
2436 : // Allow only one starting model. No additions to be done.
2437 1845 : if(startModel.nelements()>0){
2438 22 : if(deconvolver!="mtmfs"){
2439 :
2440 16 : if( startModel.nelements()!=1 ){
2441 0 : err += String("Only one startmodel image is allowed.\n");
2442 : }
2443 : else{
2444 32 : File fp(imageName+String(".model"));
2445 16 : if(fp.exists()) err += "Model " + imageName+".model exists, but a starting model of " + startModel[0] + " is also being requested. Please either reset startmodel='' to use what already exists, or delete " + imageName + ".model so that it uses the new model specified in startmodel.";
2446 16 : }
2447 : }
2448 : else{// mtmfs
2449 12 : File fp(imageName+String(".model.tt0"));
2450 6 : if(fp.exists()){
2451 0 : err += "Model " + imageName+".model.tt* exists, but a starting model of ";
2452 0 : for (uInt i=0;i<startModel.nelements();i++){err += startModel[i] + ",";}
2453 0 : err +=" is also being requested. Please either reset startmodel='' to use what already exists, or delete " + imageName + ".model.tt* so that it uses the new model specified in startmodel";
2454 : }
2455 6 : }
2456 :
2457 : // Check that startmodel exists on disk !
2458 49 : for(uInt ss=0;ss<startModel.nelements();ss++){
2459 27 : File fp( startModel[ss] );
2460 27 : if(!fp.exists()){
2461 0 : err += "Startmodel " + startModel[ss] + " cannot be found on disk.";
2462 : }
2463 27 : }
2464 : }
2465 :
2466 : /// Check imsize for efficiency.
2467 1845 : Int imxnew = SynthesisUtilMethods::getOptimumSize(imsize[0]);
2468 1845 : Int imynew = SynthesisUtilMethods::getOptimumSize(imsize[1]);
2469 1845 : if((imxnew != imsize[0] || imynew != imsize[1]) && isSingleDish == False){
2470 18 : LogIO os(LogOrigin("SynthesisParamsImage","fromRecord",WHERE));
2471 9 : if( imxnew != imsize[0] ) {
2472 2 : os << LogIO::WARN << "imsize with "+String::toString(imsize[0])+
2473 2 : " pixels is not an efficient imagesize. Try "+
2474 3 : String::toString(imxnew)+" instead." << LogIO::POST;
2475 : }
2476 9 : if( imsize[0] != imsize[1] && imynew != imsize[1] ){
2477 16 : os << LogIO::WARN << "imsize with "+String::toString(imsize[1])+
2478 16 : " pixels is not an efficient imagesize. Try "+
2479 24 : String::toString(imynew)+" instead." << LogIO::POST;
2480 : }
2481 9 : }
2482 3690 : return err;
2483 1845 : }// verify()
2484 :
2485 : /*
2486 : // Convert all user options to LSRK freqStart, freqStep,
2487 : // Could have (optional) log messages coming out of this function, to tell the user what the
2488 : // final frequency setup is ?
2489 :
2490 : String SynthesisParamsImage::verifySpectralSetup()
2491 : {
2492 : }
2493 : */
2494 :
2495 7390 : void SynthesisParamsImage::setDefaults()
2496 : {
2497 : // Image definition parameters
2498 7390 : imageName = String("");
2499 7390 : imsize.resize(2); imsize.set(100);
2500 7390 : cellsize.resize(2); cellsize.set( Quantity(1.0,"arcsec") );
2501 7390 : stokes="I";
2502 7390 : phaseCenter=MDirection();
2503 7390 : phaseCenterFieldId=-1;
2504 7390 : projection=Projection::SIN;
2505 7390 : useNCP=false;
2506 7390 : startModel=Vector<String>(0);
2507 7390 : freqFrameValid=True;
2508 7390 : overwrite=false;
2509 : // PseudoI
2510 7390 : pseudoi=false;
2511 :
2512 : // Spectral coordinates
2513 7390 : nchan=1;
2514 7390 : mode="mfs";
2515 7390 : start="";
2516 7390 : step="";
2517 7390 : chanStart=0;
2518 7390 : chanStep=1;
2519 : //freqStart=Quantity(0,"Hz");
2520 : //freqStep=Quantity(0,"Hz");
2521 : //velStart=Quantity(0,"m/s");
2522 : //velStep=Quantity(0,"m/s");
2523 7390 : freqStart=Quantity(0,"");
2524 7390 : freqStep=Quantity(0,"");
2525 7390 : velStart=Quantity(0,"");
2526 7390 : velStep=Quantity(0,"");
2527 7390 : veltype=String("radio");
2528 7390 : restFreq.resize(0);
2529 7390 : refFreq = Quantity(0,"Hz");
2530 7390 : frame = "";
2531 7390 : freqFrame=MFrequency::LSRK;
2532 7390 : sysvel="";
2533 7390 : sysvelframe="";
2534 7390 : sysvelvalue=Quantity(0.0,"m/s");
2535 7390 : nTaylorTerms=1;
2536 7390 : deconvolver="hogbom";
2537 : ///csysRecord=Record();
2538 7390 : }
2539 :
2540 899 : Record SynthesisParamsImage::toRecord() const
2541 : {
2542 899 : Record impar;
2543 899 : impar.define("imagename", imageName);
2544 899 : impar.define("imsize", imsize);
2545 899 : Vector<String> cells(2);
2546 899 : cells[0] = QuantityToString( cellsize[0] );
2547 899 : cells[1] = QuantityToString( cellsize[1] );
2548 899 : impar.define("cell", cells );
2549 899 : if(pseudoi==true){impar.define("stokes","pseudoI");}
2550 899 : else{impar.define("stokes", stokes);}
2551 899 : impar.define("nchan", nchan);
2552 899 : impar.define("nterms", nTaylorTerms);
2553 899 : impar.define("deconvolver",deconvolver);
2554 899 : impar.define("phasecenter", MDirectionToString( phaseCenter ) );
2555 899 : impar.define("phasecenterfieldid",phaseCenterFieldId);
2556 899 : impar.define("projection", (useNCP? "NCP" : projection.name()) );
2557 :
2558 899 : impar.define("specmode", mode );
2559 : // start and step can be one of these types
2560 899 : if( start!="" )
2561 : {
2562 299 : if( !start.contains("Hz") && !start.contains("m/s") &&
2563 65 : String::toInt(start) == chanStart )
2564 : {
2565 65 : impar.define("start",chanStart);
2566 : }
2567 169 : else if( startRecord.nfields() > 0 )
2568 : {
2569 25 : impar.defineRecord("start", startRecord );
2570 : }
2571 : else
2572 : {
2573 144 : impar.define("start",start);
2574 : }
2575 : }
2576 : else {
2577 665 : impar.define("start", start );
2578 : }
2579 899 : if( step!="" )
2580 : {
2581 228 : if( !step.contains("Hz") && !step.contains("m/s") &&
2582 41 : String::toInt(step) == chanStep )
2583 : {
2584 41 : impar.define("width", chanStep);
2585 : }
2586 146 : else if( stepRecord.nfields() > 0 )
2587 : {
2588 10 : impar.defineRecord("width",stepRecord);
2589 : }
2590 : else
2591 : {
2592 136 : impar.define("width",step);
2593 : }
2594 : }
2595 : else
2596 : {
2597 712 : impar.define("width", step);
2598 : }
2599 : //impar.define("chanstart", chanStart );
2600 : //impar.define("chanstep", chanStep );
2601 : //impar.define("freqstart", QuantityToString( freqStart ));
2602 : //impar.define("freqstep", QuantityToString( freqStep ) );
2603 : //impar.define("velstart", QuantityToString( velStart ));
2604 : //impar.define("velstep", QuantityToString( velStep ) );
2605 899 : impar.define("veltype", veltype);
2606 899 : if (restfreqRecord.nfields() != 0 )
2607 : {
2608 0 : impar.defineRecord("restfreq", restfreqRecord);
2609 : }
2610 : else
2611 : {
2612 899 : Vector<String> rfs( restFreq.nelements() );
2613 1086 : for(uInt rf=0; rf<restFreq.nelements(); rf++){rfs[rf] = QuantityToString(restFreq[rf]);}
2614 899 : impar.define("restfreq", rfs);
2615 899 : }
2616 : //impar.define("reffreq", QuantityToString(refFreq));
2617 : //reffreq
2618 899 : if( reffreqRecord.nfields() != 0 )
2619 0 : { impar.defineRecord("reffreq",reffreqRecord); }
2620 : else
2621 899 : { impar.define("reffreq",reffreq); }
2622 : //impar.define("reffreq", reffreq );
2623 : //impar.define("outframe", MFrequency::showType(freqFrame) );
2624 899 : impar.define("outframe", frame );
2625 : //sysvel
2626 899 : if( sysvelRecord.nfields() != 0 )
2627 0 : { impar.defineRecord("sysvel",sysvelRecord); }
2628 : else
2629 899 : { impar.define("sysvel", sysvel );}
2630 899 : impar.define("sysvelframe", sysvelframe );
2631 :
2632 899 : impar.define("restart",overwrite );
2633 899 : impar.define("freqframevalid", freqFrameValid);
2634 899 : impar.define("startmodel", startModel );
2635 :
2636 899 : if( csysRecord.isDefined("coordsys") )
2637 : {
2638 : // cout <<" HAS CSYS INFO.... writing to output record"<<endl;
2639 899 : impar.defineRecord("csys", csysRecord.subRecord("coordsys"));
2640 899 : impar.define("imshape", imshape);
2641 : }
2642 : // else cout << " NO CSYS INFO to write to output record " << endl;
2643 : ///Now save obslocation
2644 899 : Record tmprec;
2645 899 : String err;
2646 899 : MeasureHolder mh(obslocation);
2647 899 : if(mh.toRecord(err, tmprec)){
2648 899 : impar.defineRecord("obslocation_rec", tmprec);
2649 : }
2650 : else{
2651 0 : throw(AipsError("failed to save obslocation to record"));
2652 : }
2653 1798 : return impar;
2654 899 : }
2655 :
2656 : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2657 : /////////////////////////// Build a coordinate system. ////////////////////////////////////////
2658 : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2659 : //// To be used from SynthesisImager, to construct the images it needs
2660 : //// To also be connected to a 'makeimage' method of the synthesisimager tool.
2661 : //// ( need to supply MS only to add 'ObsInfo' to the csys )
2662 : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2663 :
2664 :
2665 :
2666 943 : CoordinateSystem SynthesisParamsImage::buildCoordinateSystem(vi::VisibilityIterator2& vi2, const std::map<Int, std::map<Int, Vector<Int> > >& chansel, Block<const MeasurementSet *> mss)
2667 :
2668 : {
2669 : //vi2.getImpl()->spectralWindows( spwids );
2670 : //The above is not right
2671 : //////////// ///Kludge to find all spw selected
2672 : //std::vector<Int> pushspw;
2673 943 : vi::VisBuffer2* vb=vi2.getVisBuffer();
2674 943 : vi2.originChunks();
2675 943 : vi2.origin();
2676 : /// This version uses the new vi2/vb2
2677 : // get the first ms for multiple MSes
2678 : //MeasurementSet msobj=vi2.ms();
2679 943 : Int fld=vb->fieldId()(0);
2680 :
2681 : //handling first ms only
2682 943 : Double gfreqmax=-1.0;
2683 943 : Double gdatafend=-1.0;
2684 943 : Double gdatafstart=1e14;
2685 943 : Double gfreqmin=1e14;
2686 943 : Vector<Int> spwids0;
2687 943 : Int j=0;
2688 943 : Int minfmsid=0;
2689 : //for cube mode ,for a list of MSs, check ms to send to buildCoordSysCore contains start freq/vel
2690 943 : Double imStartFreq=getCubeImageStartFreq();
2691 943 : std::vector<Int> sourceMsWithStartFreq;
2692 :
2693 :
2694 1950 : for (auto forMS0=chansel.begin(); forMS0 !=chansel.end(); ++forMS0, ++j){
2695 : //auto forMS0=chansel.find(0);
2696 1007 : map<Int, Vector<Int> > spwsels=forMS0->second;
2697 1007 : Int nspws=spwsels.size();
2698 1007 : Vector<Int> spwids(nspws);
2699 1007 : Vector<Int> nChannels(nspws);
2700 1007 : Vector<Int> firstChannels(nspws);
2701 : //Vector<Int> channelIncrement(nspws);
2702 :
2703 1007 : Int k=0;
2704 2297 : for (auto it=spwsels.begin(); it != spwsels.end(); ++it, ++k){
2705 1290 : spwids[k]=it->first;
2706 1290 : nChannels[k]=(it->second)[0];
2707 1290 : firstChannels[k]=(it->second)[1];
2708 : }
2709 1007 : if(j==0) {
2710 943 : spwids0.resize();
2711 943 : spwids0=spwids;
2712 : }
2713 : // std::tie (spwids, nChannels, firstChannels, channelIncrement)=(static_cast<vi::VisibilityIteratorImpl2 * >(vi2.getImpl()))->getChannelInformation(false);
2714 :
2715 : //cerr << "SPWIDS "<< spwids << " nchan " << nChannels << " firstchan " << firstChannels << endl;
2716 :
2717 : //////////////////This returns junk for multiple ms CAS-9994..so kludged up along with spw kludge
2718 : //Vector<Int> flds;
2719 : //vi2.getImpl()->fieldIds( flds );
2720 : //AlwaysAssert( flds.nelements()>0 , AipsError );
2721 : //fld = flds[0];
2722 1007 : Double freqmin=0, freqmax=0;
2723 1007 : freqFrameValid=(freqFrame != MFrequency::REST || mode=="cubesource");
2724 :
2725 : //MFrequency::Types dataFrame=(MFrequency::Types)vi2.subtableColumns().spectralWindow().measFreqRef()(spwids[0]);
2726 1007 : MFrequency::Types dataFrame=(MFrequency::Types)MSColumns(*mss[j]).spectralWindow().measFreqRef()(spwids[0]);
2727 :
2728 : Double datafstart, datafend;
2729 : //VisBufferUtil::getFreqRange(datafstart, datafend, vi2, dataFrame );
2730 : //cerr << std::setprecision(12) << "before " << datafstart << " " << datafend << endl;
2731 1007 : Bool status=MSUtil::getFreqRangeInSpw( datafstart, datafend, spwids, firstChannels, nChannels,*mss[j], dataFrame, True);
2732 : //cerr << "after " << datafstart << " " << datafend << endl;
2733 1007 : if((datafstart > datafend) || !status)
2734 0 : throw(AipsError("spw selection failed"));
2735 : //cerr << "datafstart " << datafstart << " end " << datafend << endl;
2736 :
2737 1007 : if (mode=="cubedata") {
2738 2 : freqmin = datafstart;
2739 2 : freqmax = datafend;
2740 : }
2741 1005 : else if(mode == "cubesource"){
2742 5 : if(!trackSource){
2743 0 : throw(AipsError("Cannot be in cubesource without tracking a moving source"));
2744 : }
2745 5 : String ephemtab(movingSource);
2746 5 : if(movingSource=="TRACKFIELD"){
2747 3 : Int fieldID=MSColumns(*mss[j]).fieldId()(0);
2748 3 : ephemtab=Path(MSColumns(*mss[j]).field().ephemPath(fieldID)).absoluteName();
2749 : }
2750 5 : MEpoch refep=MSColumns(*mss[j]).timeMeas()(0);
2751 5 : Quantity refsysvel;
2752 5 : MSUtil::getFreqRangeAndRefFreqShift(freqmin,freqmax,refsysvel, refep, spwids,firstChannels, nChannels, *mss[j], ephemtab, trackDir, true);
2753 5 : if(j==0)
2754 5 : sysvelvalue=refsysvel;
2755 : /*Double freqMinTopo, freqMaxTopo;
2756 : MSUtil::getFreqRangeInSpw( freqMinTopo, freqMaxTopo, spwids, firstChannels,
2757 : nChannels,*mss[j], freqFrameValid? MFrequency::TOPO:MFrequency::REST , True);
2758 : cerr << std::setprecision(10) << (freqmin-freqMinTopo) << " " << (freqmax-freqMaxTopo) << endl;
2759 : sysfreqshift=((freqmin-freqMinTopo)+(freqmax-freqMaxTopo))/2.0;
2760 : */
2761 5 : }
2762 : else {
2763 : //VisBufferUtil::getFreqRange(freqmin,freqmax, vi2, freqFrameValid? freqFrame:MFrequency::REST );
2764 : //cerr << "before " << freqmin << " " << freqmax << endl;
2765 2000 : MSUtil::getFreqRangeInSpw( freqmin, freqmax, spwids, firstChannels,
2766 2000 : nChannels,*mss[j], freqFrameValid? freqFrame:MFrequency::REST , True);
2767 : //cerr << "after " << freqmin << " " << freqmax << endl;
2768 : }
2769 :
2770 :
2771 :
2772 :
2773 1007 : if(freqmin < gfreqmin) gfreqmin=freqmin;
2774 1007 : if(freqmax > gfreqmax) gfreqmax=freqmax;
2775 1007 : if(datafstart < gdatafstart) gdatafstart=datafstart;
2776 1007 : if(datafend > gdatafend) gdatafend=datafend;
2777 : // pick ms to use for setting spectral coord for output images
2778 : // when startfreq is specified find first ms that it fall within the freq range
2779 : // of the ms (with channel selection applied).
2780 : // startfreq is converted to the data frame freq based on Measure ref (for the direction, epech, location)
2781 : // of that ms.
2782 1007 : if(imStartFreq > 0.0 && imStartFreq >= freqmin && imStartFreq <= freqmax){
2783 72 : if(mode != "cubesource"){
2784 72 : minfmsid=j;
2785 72 : spwids0.resize();
2786 72 : spwids0=spwids;
2787 72 : vi2.originChunks();
2788 72 : vi2.origin();
2789 74 : while(vb->msId() != j && vi2.moreChunks() ){
2790 2 : vi2.nextChunk();
2791 2 : vi2.origin();
2792 : }
2793 72 : fld=vb->fieldId()(0);
2794 :
2795 : }
2796 : else{
2797 0 : sourceMsWithStartFreq.push_back(j);
2798 : }
2799 : }
2800 :
2801 1007 : }
2802 943 : if(sourceMsWithStartFreq.size() > 1){
2803 0 : auto result = std::find(std::begin(sourceMsWithStartFreq), std::end(sourceMsWithStartFreq), 0);
2804 0 : if(result == std::end(sourceMsWithStartFreq)){
2805 0 : throw(AipsError("Reorder the input list of MSs so that MS "+String::toString( sourceMsWithStartFreq[0])+ "is first to match startfreq you provided"));
2806 : }
2807 : }
2808 943 : MeasurementSet msobj = *mss[minfmsid];
2809 : // return buildCoordinateSystemCore( msobj, spwids0, fld, gfreqmin, gfreqmax, gdatafstart, gdatafend );
2810 1886 : return buildCoordinateSystemCore( msobj, spwids0, fld, gfreqmin, gfreqmax, gdatafstart, gdatafend );
2811 945 : }
2812 :
2813 :
2814 0 : CoordinateSystem SynthesisParamsImage::buildCoordinateSystem(ROVisibilityIterator* rvi )
2815 : {
2816 : /// This version uses the old vi/vb
2817 : // get the first ms for multiple MSes
2818 0 : MeasurementSet msobj=rvi->getMeasurementSet();
2819 0 : Vector<Int> spwids;
2820 0 : Vector<Int> nvischan;
2821 0 : rvi->allSelectedSpectralWindows(spwids,nvischan);
2822 0 : Int fld = rvi->fieldId();
2823 0 : Double freqmin=0, freqmax=0;
2824 : Double datafstart, datafend;
2825 : //freqFrameValid=(freqFrame != MFrequency::REST || mode != "cubedata" );
2826 0 : freqFrameValid=(freqFrame != MFrequency::REST );
2827 0 : MSColumns msc(msobj);
2828 0 : MFrequency::Types dataFrame=(MFrequency::Types)msc.spectralWindow().measFreqRef()(spwids[0]);
2829 0 : rvi->getFreqInSpwRange(datafstart, datafend, dataFrame );
2830 0 : if (mode=="cubedata") {
2831 0 : freqmin = datafstart;
2832 0 : freqmax = datafend;
2833 : }
2834 : else {
2835 0 : rvi->getFreqInSpwRange(freqmin,freqmax,freqFrameValid? freqFrame:MFrequency::REST );
2836 : }
2837 : // Following three lines are kind of redundant but need to get freq range in the data frame to be used
2838 : // to select channel range for default start
2839 : //cerr<<"freqmin="<<freqmin<<" datafstart="<<datafstart<<" freqmax="<<freqmax<<" datafend="<<datafend<<endl;
2840 0 : return buildCoordinateSystemCore( msobj, spwids, fld, freqmin, freqmax, datafstart, datafend );
2841 0 : }
2842 :
2843 943 : CoordinateSystem SynthesisParamsImage::buildCoordinateSystemCore(
2844 : MeasurementSet& msobj,
2845 : Vector<Int> spwids, Int fld,
2846 : Double freqmin, Double freqmax,
2847 : Double datafstart, Double datafend )
2848 : {
2849 1886 : LogIO os( LogOrigin("SynthesisParamsImage","buildCoordinateSystem",WHERE) );
2850 :
2851 943 : CoordinateSystem csys;
2852 943 : if( csysRecord.nfields()!=0 )
2853 : {
2854 : //use cysRecord
2855 1 : Record subRec1;
2856 : // cout<<"USE THE EXISTING CSYS +++++++++++++++++"<<endl;
2857 1 : CoordinateSystem *csysptr = CoordinateSystem::restore(csysRecord,"coordsys");
2858 : //csys = *csysptr;
2859 : //CoordinateSystem csys(*csysptr);
2860 1 : csys = *csysptr;
2861 :
2862 1 : }
2863 : else {
2864 942 : MSColumns msc(msobj);
2865 942 : String telescop = msc.observation().telescopeName()(0);
2866 942 : MEpoch obsEpoch = msc.timeMeas()(0);
2867 942 : MPosition obsPosition;
2868 942 : if(!(MeasTable::Observatory(obsPosition, telescop)))
2869 : {
2870 : os << LogIO::WARN << "Did not get the position of " << telescop
2871 0 : << " from data repository" << LogIO::POST;
2872 : os << LogIO::WARN
2873 : << "Please contact CASA to add it to the repository."
2874 0 : << LogIO::POST;
2875 0 : os << LogIO::WARN << "Using first antenna position as refence " << LogIO::POST;
2876 : // unknown observatory, use first antenna
2877 0 : obsPosition=msc.antenna().positionMeas()(0);
2878 : }
2879 942 : MDirection phaseCenterToUse = phaseCenter;
2880 :
2881 942 : if( phaseCenterFieldId != -1 )
2882 : {
2883 596 : MSFieldColumns msfield(msobj.field());
2884 596 : if(phaseCenterFieldId == -2) // the case for phasecenter=''
2885 : {
2886 570 : if(trackSource){
2887 14 : phaseCenterToUse=getMovingSourceDir(msobj, obsEpoch, obsPosition, MDirection::ICRS);
2888 : }
2889 : else{
2890 556 : phaseCenterToUse=msfield.phaseDirMeas( fld );
2891 : }
2892 : }
2893 : else
2894 : {
2895 26 : phaseCenterToUse=msfield.phaseDirMeas( phaseCenterFieldId );
2896 : }
2897 596 : }
2898 : // Setup Phase center if it is specified only by field id.
2899 :
2900 : /////////////////// Direction Coordinates
2901 942 : MVDirection mvPhaseCenter(phaseCenterToUse.getAngle());
2902 : // Normalize correctly
2903 942 : MVAngle ra=mvPhaseCenter.get()(0);
2904 942 : ra(0.0);
2905 :
2906 942 : MVAngle dec=mvPhaseCenter.get()(1);
2907 942 : Vector<Double> refCoord(2);
2908 942 : refCoord(0)=ra.get().getValue();
2909 942 : refCoord(1)=dec;
2910 942 : Vector<Double> refPixel(2);
2911 942 : refPixel(0) = Double(imsize[0]/2);
2912 942 : refPixel(1) = Double(imsize[1]/2);
2913 :
2914 942 : Vector<Double> deltas(2);
2915 942 : deltas(0)=-1* cellsize[0].get("rad").getValue();
2916 942 : deltas(1)=cellsize[1].get("rad").getValue();
2917 942 : Matrix<Double> xform(2,2);
2918 942 : xform=0.0;xform.diagonal()=1.0;
2919 :
2920 942 : Vector<Double> projparams(2);
2921 942 : projparams = 0.0;
2922 942 : if( useNCP==true ) { projparams[0]=0.0, projparams[1]=1/tan(refCoord(1)); }
2923 942 : Projection projTo( projection.type(), projparams );
2924 :
2925 : DirectionCoordinate
2926 942 : myRaDec(MDirection::Types(phaseCenterToUse.getRefPtr()->getType()),
2927 : // projection,
2928 : projTo,
2929 2826 : refCoord(0), refCoord(1),
2930 2826 : deltas(0), deltas(1),
2931 : xform,
2932 1884 : refPixel(0), refPixel(1));
2933 :
2934 :
2935 : //defining observatory...needed for position on earth
2936 : // get the first ms for multiple MSes
2937 :
2938 :
2939 942 : obslocation=obsPosition;
2940 942 : ObsInfo myobsinfo;
2941 942 : myobsinfo.setTelescope(telescop);
2942 942 : myobsinfo.setPointingCenter(mvPhaseCenter);
2943 942 : myobsinfo.setObsDate(obsEpoch);
2944 942 : myobsinfo.setObserver(msc.observation().observer()(0));
2945 :
2946 : /// Attach obsInfo to the CoordinateSystem
2947 : ///csys.setObsInfo(myobsinfo);
2948 :
2949 :
2950 : /////////////////// Spectral Coordinate
2951 :
2952 : //Make sure frame conversion is switched off for REST frame data.
2953 : //Bool freqFrameValid=(freqFrame != MFrequency::REST);
2954 :
2955 : //freqFrameValid=(freqFrame != MFrequency::REST );
2956 : //UR//freqFrameValid=(freqFrame != MFrequency::REST || mode != "cubedata" );
2957 : //UR - moved freqFrameValid calc to vi/vi2 dependent wrappers.
2958 :
2959 942 : if(spwids.nelements()==0)
2960 : {
2961 0 : Int nspw=msc.spectralWindow().nrow();
2962 0 : spwids.resize(nspw);
2963 0 : indgen(spwids);
2964 : }
2965 942 : MFrequency::Types dataFrame=(MFrequency::Types)msc.spectralWindow().measFreqRef()(spwids[0]);
2966 942 : Vector<Double> dataChanFreq, dataChanWidth;
2967 942 : std::vector<std::vector<Int> > averageWhichChan;
2968 942 : std::vector<std::vector<Int> > averageWhichSPW;
2969 942 : std::vector<std::vector<Double> > averageChanFrac;
2970 :
2971 942 : if(spwids.nelements()==1)
2972 : {
2973 787 : dataChanFreq=msc.spectralWindow().chanFreq()(spwids[0]);
2974 787 : dataChanWidth=msc.spectralWindow().chanWidth()(spwids[0]);
2975 : }
2976 : else
2977 : {
2978 155 : if(!MSTransformRegridder::combineSpwsCore(os,msobj, spwids,dataChanFreq,dataChanWidth,
2979 : averageWhichChan,averageWhichSPW,averageChanFrac))
2980 : {
2981 0 : os << LogIO::SEVERE << "Error combining SpWs" << LogIO::POST;
2982 : }
2983 : }
2984 942 : Double minDataFreq = min(dataChanFreq);
2985 942 : if(start=="" && minDataFreq < datafstart ) {
2986 : // limit data chan freq vector for default start case with channel selection
2987 : Int chanStart, chanEnd;
2988 6 : Int lochan = 0;
2989 6 : Int nDataChan = dataChanFreq.nelements();
2990 6 : Int hichan = nDataChan-1;
2991 : Double diff_fmin, diff_fmax;
2992 6 : Bool ascending = dataChanFreq[nDataChan-1] - dataChanFreq[0] > 0;
2993 90 : for(Int ichan = 0; ichan < nDataChan; ichan++)
2994 : {
2995 84 : diff_fmin = dataChanFreq[ichan] - datafstart;
2996 84 : diff_fmax = datafend - dataChanFreq[ichan];
2997 : // freqmin and freqmax should corresponds to the channel edges
2998 84 : if(ascending)
2999 : {
3000 :
3001 84 : if( diff_fmin > 0 && diff_fmin <= dataChanWidth[ichan]/2. )
3002 : {
3003 6 : lochan = ichan;
3004 : }
3005 78 : else if(diff_fmax > 0 && diff_fmax <= dataChanWidth[ichan]/2. )
3006 : {
3007 4 : hichan = ichan;
3008 : }
3009 : }
3010 : else
3011 : {
3012 0 : if( diff_fmax > 0 && diff_fmax <= dataChanWidth[ichan]/2. )
3013 : {
3014 0 : hichan = ichan;
3015 : }
3016 0 : else if( diff_fmin > 0 && diff_fmin <= dataChanWidth[ichan]/2. )
3017 : {
3018 0 : lochan = ichan;
3019 : }
3020 : }
3021 : }
3022 6 : chanStart = lochan;
3023 6 : chanEnd = hichan;
3024 6 : if (lochan > hichan)
3025 : {
3026 0 : chanStart=hichan;
3027 0 : chanEnd=lochan;
3028 : }
3029 6 : Vector<Double> tempChanFreq = dataChanFreq(Slice(chanStart,chanEnd-chanStart+1,1));
3030 6 : Vector<Double> tempChanWidth = dataChanWidth(Slice(chanStart,chanEnd-chanStart+1,1));
3031 6 : dataChanFreq.resize(tempChanFreq.nelements());
3032 6 : dataChanWidth.resize(tempChanWidth.nelements());
3033 6 : dataChanFreq = tempChanFreq;
3034 6 : dataChanWidth = tempChanWidth;
3035 6 : }
3036 942 : Quantity qrestfreq = restFreq.nelements() >0 ? restFreq[0]: Quantity(0.0, "Hz");
3037 942 : String cubemode;
3038 942 : if ( qrestfreq.getValue("Hz")==0 )
3039 : {
3040 868 : MSDopplerUtil msdoppler(msobj);
3041 868 : Vector<Double> restfreqvec;
3042 868 : msdoppler.dopplerInfo(restfreqvec, spwids(0), fld);
3043 868 : qrestfreq = restfreqvec.nelements() >0 ? Quantity(restfreqvec(0),"Hz"): Quantity(0.0, "Hz");
3044 868 : if ( qrestfreq.getValue("Hz")==0 and mode!="mfs" )
3045 : {
3046 90 : cubemode = findSpecMode(mode);
3047 90 : if ( cubemode=="channel" || cubemode=="frequency" )
3048 : {
3049 : //Double provisional_restfreq = msc.spectralWindow().refFrequency()(spwids(0));
3050 : //By PLWG request, changed to center (mean) frequency of the selected spws -2015-06-22(TT)
3051 90 : Double provisional_restfreq = (datafend+datafstart)/2.0;
3052 90 : qrestfreq = Quantity(provisional_restfreq, "Hz");
3053 : os << LogIO::WARN << "No rest frequency info, using the center of the selected spw(s):"
3054 : << provisional_restfreq <<" Hz. Velocity labelling may not be correct."
3055 90 : << LogIO::POST;
3056 : }
3057 : else { // must be vel mode
3058 0 : throw(AipsError("No valid rest frequency is defined in the data, please specify the restfreq parameter") );
3059 : }
3060 : }
3061 868 : }
3062 : Double refPix;
3063 942 : Vector<Double> chanFreq;
3064 942 : Vector<Double> chanFreqStep;
3065 942 : String specmode;
3066 :
3067 942 : if(mode=="cubesource"){
3068 5 : MDoppler mdop(sysvelvalue, MDoppler::RELATIVISTIC);
3069 5 : dataChanFreq=mdop.shiftFrequency(dataChanFreq);
3070 5 : dataChanWidth=mdop.shiftFrequency(dataChanWidth);
3071 5 : if (std::isnan(dataChanFreq[0]) || std::isnan(dataChanFreq[dataChanFreq.nelements()-1])) {
3072 0 : throw(AipsError("The Doppler shift correction of the data channel frequencies resulted in 'NaN' using the radial velocity = "+
3073 0 : String::toString(sysvelvalue)+". Typically this indicates a problem in the ephemeris data being used."));
3074 : }
3075 5 : }
3076 :
3077 942 : if (!getImFreq(chanFreq, chanFreqStep, refPix, specmode, obsEpoch,
3078 : obsPosition, dataChanFreq, dataChanWidth, dataFrame, qrestfreq, freqmin, freqmax,
3079 : phaseCenterToUse))
3080 0 : throw(AipsError("Failed to determine channelization parameters"));
3081 :
3082 941 : Bool nonLinearFreq(false);
3083 941 : String veltype_p=veltype;
3084 941 : veltype_p.upcase();
3085 2819 : if(veltype_p.contains("OPTICAL") || veltype_p.matches("Z") || veltype_p.contains("BETA") ||
3086 2819 : veltype_p.contains("RELATI") || veltype_p.contains("GAMMA"))
3087 : {
3088 2 : nonLinearFreq= true;
3089 : }
3090 :
3091 941 : SpectralCoordinate mySpectral;
3092 : Double stepf;
3093 941 : if(!nonLinearFreq)
3094 : //TODO: velocity mode default start case (use last channels?)
3095 : {
3096 939 : Double startf=chanFreq[0];
3097 : //Double stepf=chanFreqStep[0];
3098 939 : if(chanFreq.nelements()==1)
3099 : {
3100 584 : stepf=chanFreqStep[0];
3101 : }
3102 : else
3103 : {
3104 355 : stepf=chanFreq[1]-chanFreq[0];
3105 : }
3106 939 : Double restf=qrestfreq.getValue("Hz");
3107 : //stepf=9e8;
3108 939 : if ( mode=="mfs" and restf == 0.0 ) restf = restFreq[0].getValue("Hz");
3109 : //cerr<<" startf="<<startf<<" stepf="<<stepf<<" refPix="<<refPix<<" restF="<<restf<<endl;
3110 : // once NOFRAME is implemented do this
3111 939 : if(mode=="cubedata")
3112 : {
3113 : // mySpectral = SpectralCoordinate(freqFrameValid ? MFrequency::Undefined : MFrequency::REST,
3114 4 : mySpectral = SpectralCoordinate(freqFrame == MFrequency::REST?
3115 : MFrequency::REST : MFrequency::Undefined,
3116 2 : startf, stepf, refPix, restf);
3117 : }
3118 937 : else if(mode=="cubesource")
3119 : {
3120 : /*stepf=chanFreq.nelements() > 1 ?(freqmax-freqmin)/Double(chanFreq.nelements()-1) : freqmax-freqmin;
3121 : startf=freqmin+stepf/2.0;
3122 : */
3123 10 : mySpectral = SpectralCoordinate(MFrequency::REST,
3124 5 : startf, stepf, refPix, restf);
3125 : }
3126 : else
3127 : {
3128 1864 : mySpectral = SpectralCoordinate(freqFrameValid ? freqFrame : MFrequency::REST,
3129 932 : startf, stepf, refPix, restf);
3130 : }
3131 : }
3132 : else
3133 : { // nonlinear freq coords - use tabular setting
3134 : // once NOFRAME is implemented do this
3135 2 : if(mode=="cubedata")
3136 : {
3137 : //mySpectral = SpectralCoordinate(freqFrameValid ? MFrequency::Undefined : MFrequency::REST,
3138 0 : mySpectral = SpectralCoordinate(freqFrame == MFrequency::REST ?
3139 : MFrequency::REST : MFrequency::Undefined,
3140 0 : chanFreq, (Double)qrestfreq.getValue("Hz"));
3141 : }
3142 2 : else if (mode=="cubesource")
3143 : {
3144 0 : mySpectral = SpectralCoordinate(MFrequency::REST,
3145 0 : chanFreq, (Double)qrestfreq.getValue("Hz"));
3146 : }
3147 : else
3148 : {
3149 4 : mySpectral = SpectralCoordinate(freqFrameValid ? freqFrame : MFrequency::REST,
3150 6 : chanFreq, (Double)qrestfreq.getValue("Hz"));
3151 : }
3152 : }
3153 : //cout << "Rest Freq : " << restFreq << endl;
3154 :
3155 : //for(uInt k=1 ; k < restFreq.nelements(); ++k)
3156 : //mySpectral.setRestFrequency(restFreq[k].getValue("Hz"));
3157 :
3158 941 : uInt nrestfreq = restFreq.nelements();
3159 941 : if ( nrestfreq > 1 ) {
3160 0 : Vector<Double> restfreqval( nrestfreq - 1 );
3161 0 : for ( uInt k=1 ; k < nrestfreq; ++k ) {
3162 0 : restfreqval[k-1] = restFreq[k].getValue("Hz");
3163 : }
3164 0 : mySpectral.setRestFrequencies(restfreqval, 0, true);
3165 0 : }
3166 :
3167 : // no longer needed, done inside SIImageStore
3168 : //if ( freqFrameValid ) {
3169 : // mySpectral.setReferenceConversion(MFrequency::LSRK,obsEpoch,obsPosition,phaseCenterToUse);
3170 : //}
3171 :
3172 : // cout << "RF from coordinate : " << mySpectral.restFrequency() << endl;
3173 :
3174 : ////////////////// Stokes Coordinate
3175 :
3176 941 : Vector<Int> whichStokes = decideNPolPlanes(stokes);
3177 941 : if(whichStokes.nelements()==0)
3178 0 : throw(AipsError("Stokes selection of " + stokes + " is invalid"));
3179 941 : StokesCoordinate myStokes(whichStokes);
3180 :
3181 : ////////////////// Build Full coordinate system.
3182 :
3183 : //CoordinateSystem csys;
3184 941 : csys.addCoordinate(myRaDec);
3185 941 : csys.addCoordinate(myStokes);
3186 941 : csys.addCoordinate(mySpectral);
3187 941 : csys.setObsInfo(myobsinfo);
3188 :
3189 : //store back csys to impars record
3190 : //cerr<<"save csys to csysRecord..."<<endl;
3191 941 : if(csysRecord.isDefined("coordsys"))
3192 0 : csysRecord.removeField("coordsys");
3193 941 : csys.save(csysRecord,"coordsys");
3194 : //cerr<<"BUILDCOORDSYS:: new csysRecord ="<<csysRecord<<endl;
3195 : // imshape
3196 941 : imshape.resize(4);
3197 941 : imshape[0] = imsize[0];
3198 941 : imshape[1] = imsize[0];
3199 941 : imshape[2] = whichStokes.nelements();
3200 941 : imshape[3] = chanFreq.nelements();
3201 : //toRecord();
3202 : //////////////// Set Observatory info, if MS is provided.
3203 : // (remove this section after verified...)
3204 : /***
3205 : if( ! msobj.isNull() )
3206 : {
3207 : //defining observatory...needed for position on earth
3208 : MSColumns msc(msobj);
3209 : String telescop = msc.observation().telescopeName()(0);
3210 : MEpoch obsEpoch = msc.timeMeas()(0);
3211 : MPosition obsPosition;
3212 : if(!(MeasTable::Observatory(obsPosition, telescop)))
3213 : {
3214 : os << LogIO::WARN << "Did not get the position of " << telescop
3215 : << " from data repository" << LogIO::POST;
3216 : os << LogIO::WARN
3217 : << "Please contact CASA to add it to the repository."
3218 : << LogIO::POST;
3219 : os << LogIO::WARN << "Frequency conversion will not work " << LogIO::POST;
3220 : }
3221 :
3222 : ObsInfo myobsinfo;
3223 : myobsinfo.setTelescope(telescop);
3224 : myobsinfo.setPointingCenter(mvPhaseCenter);
3225 : myobsinfo.setObsDate(obsEpoch);
3226 : myobsinfo.setObserver(msc.observation().observer()(0));
3227 :
3228 : /// Attach obsInfo to the CoordinateSystem
3229 : csys.setObsInfo(myobsinfo);
3230 :
3231 : }// if MS is provided.
3232 : ***/
3233 967 : } // end of else when coordsys record is not defined...
3234 :
3235 : // cout << " ----- ----- ------ ------ CSYS WORLD AXIS UNITS : " << csys.worldAxisUnits() << endl;
3236 :
3237 1884 : return csys;
3238 944 : }
3239 :
3240 :
3241 : /*
3242 : #ifdef USEVIVB2
3243 : CoordinateSystem SynthesisParamsImage::buildCoordinateSystem(vi::VisibilityIterator2* vi2)
3244 : #else
3245 : CoordinateSystem SynthesisParamsImage::buildCoordinateSystem(ROVisibilityIterator* rvi )
3246 : #endif
3247 : {
3248 : LogIO os( LogOrigin("SynthesisParamsImage","buildCoordinateSystem",WHERE) );
3249 :
3250 :
3251 : // get the first ms for multiple MSes
3252 : #ifdef USEVIVB2
3253 : MeasurementSet msobj=vi2->getMeasurementSet();
3254 : #else
3255 : MeasurementSet msobj=rvi->getMeasurementSet();
3256 : #endif
3257 :
3258 : MDirection phaseCenterToUse = phaseCenter;
3259 : if( phaseCenterFieldId != -1 )
3260 : {
3261 : MSFieldColumns msfield(msobj.field());
3262 : phaseCenterToUse=msfield.phaseDirMeas( phaseCenterFieldId );
3263 : }
3264 : // Setup Phase center if it is specified only by field id.
3265 :
3266 : /////////////////// Direction Coordinates
3267 : MVDirection mvPhaseCenter(phaseCenterToUse.getAngle());
3268 : // Normalize correctly
3269 : MVAngle ra=mvPhaseCenter.get()(0);
3270 : ra(0.0);
3271 :
3272 : MVAngle dec=mvPhaseCenter.get()(1);
3273 : Vector<Double> refCoord(2);
3274 : refCoord(0)=ra.get().getValue();
3275 : refCoord(1)=dec;
3276 : Vector<Double> refPixel(2);
3277 : refPixel(0) = Double(imsize[0]/2);
3278 : refPixel(1) = Double(imsize[1]/2);
3279 :
3280 : Vector<Double> deltas(2);
3281 : deltas(0)=-1* cellsize[0].get("rad").getValue();
3282 : deltas(1)=cellsize[1].get("rad").getValue();
3283 : Matrix<Double> xform(2,2);
3284 : xform=0.0;xform.diagonal()=1.0;
3285 :
3286 : Vector<Double> projparams(2);
3287 : projparams = 0.0;
3288 : if( useNCP==true ) { projparams[0]=0.0, projparams[1]=1/tan(refCoord(1)); }
3289 : Projection projTo( projection.type(), projparams );
3290 :
3291 : DirectionCoordinate
3292 : myRaDec(MDirection::Types(phaseCenterToUse.getRefPtr()->getType()),
3293 : // projection,
3294 : projTo,
3295 : refCoord(0), refCoord(1),
3296 : deltas(0), deltas(1),
3297 : xform,
3298 : refPixel(0), refPixel(1));
3299 :
3300 :
3301 : //defining observatory...needed for position on earth
3302 : // get the first ms for multiple MSes
3303 : MSColumns msc(msobj);
3304 : String telescop = msc.observation().telescopeName()(0);
3305 : MEpoch obsEpoch = msc.timeMeas()(0);
3306 : MPosition obsPosition;
3307 : if(!(MeasTable::Observatory(obsPosition, telescop)))
3308 : {
3309 : os << LogIO::WARN << "Did not get the position of " << telescop
3310 : << " from data repository" << LogIO::POST;
3311 : os << LogIO::WARN
3312 : << "Please contact CASA to add it to the repository."
3313 : << LogIO::POST;
3314 : os << LogIO::WARN << "Frequency conversion will not work " << LogIO::POST;
3315 : }
3316 :
3317 : ObsInfo myobsinfo;
3318 : myobsinfo.setTelescope(telescop);
3319 : myobsinfo.setPointingCenter(mvPhaseCenter);
3320 : myobsinfo.setObsDate(obsEpoch);
3321 : myobsinfo.setObserver(msc.observation().observer()(0));
3322 :
3323 : /// Attach obsInfo to the CoordinateSystem
3324 : ///csys.setObsInfo(myobsinfo);
3325 :
3326 :
3327 : /////////////////// Spectral Coordinate
3328 :
3329 : //Make sure frame conversion is switched off for REST frame data.
3330 : //Bool freqFrameValid=(freqFrame != MFrequency::REST);
3331 :
3332 : //freqFrameValid=(freqFrame != MFrequency::REST );
3333 : freqFrameValid=(freqFrame != MFrequency::REST || mode != "cubedata" );
3334 :
3335 : // *** get selected spw ids ***
3336 : Vector<Int> spwids;
3337 : #ifdef USEVIVB2
3338 : vi2->spectralWindows( spwids );
3339 : #else
3340 : Vector<Int> nvischan;
3341 : rvi->allSelectedSpectralWindows(spwids,nvischan);
3342 : #endif
3343 : if(spwids.nelements()==0)
3344 : {
3345 : Int nspw=msc.spectralWindow().nrow();
3346 : spwids.resize(nspw);
3347 : indgen(spwids);
3348 : }
3349 : MFrequency::Types dataFrame=(MFrequency::Types)msc.spectralWindow().measFreqRef()(spwids[0]);
3350 : Vector<Double> dataChanFreq, dataChanWidth;
3351 : if(spwids.nelements()==1)
3352 : {
3353 : dataChanFreq=msc.spectralWindow().chanFreq()(spwids[0]);
3354 : dataChanWidth=msc.spectralWindow().chanWidth()(spwids[0]);
3355 : }
3356 : else
3357 : {
3358 : SubMS thems(msobj);
3359 : if(!thems.combineSpws(spwids,true,dataChanFreq,dataChanWidth))
3360 : //if(!MSTransformRegridder::combineSpws(os,msobj.tableName(),spwids,dataChanFreq,dataChanWidth))
3361 : {
3362 : os << LogIO::SEVERE << "Error combining SpWs" << LogIO::POST;
3363 : }
3364 : }
3365 :
3366 : Quantity qrestfreq = restFreq.nelements() >0 ? restFreq[0]: Quantity(0.0, "Hz");
3367 : if( qrestfreq.getValue("Hz")==0 )
3368 : {
3369 : #ifdef USEVIVB2
3370 : ///// TTCheck
3371 : Vector<Int> flds;
3372 : vi2->fieldIds( flds );
3373 : AlwaysAssert( flds.nelements()>0 , AipsError );
3374 : Int fld = flds[0];
3375 : #else
3376 : Int fld = rvi->fieldId();
3377 : #endif
3378 : MSDopplerUtil msdoppler(msobj);
3379 : Vector<Double> restfreqvec;
3380 : msdoppler.dopplerInfo(restfreqvec, spwids[0], fld);
3381 : qrestfreq = restfreqvec.nelements() >0 ? Quantity(restfreqvec[0],"Hz"): Quantity(0.0, "Hz");
3382 : }
3383 : Double refPix;
3384 : Vector<Double> chanFreq;
3385 : Vector<Double> chanFreqStep;
3386 : String specmode;
3387 :
3388 : //for mfs
3389 : Double freqmin=0, freqmax=0;
3390 : #ifdef USEVIVB2
3391 : vi2->getFreqInSpwRange(freqmin,freqmax,freqFrameValid? freqFrame:MFrequency::REST );
3392 : #else
3393 : rvi->getFreqInSpwRange(freqmin,freqmax,freqFrameValid? freqFrame:MFrequency::REST );
3394 : #endif
3395 :
3396 : if (!getImFreq(chanFreq, chanFreqStep, refPix, specmode, obsEpoch,
3397 : obsPosition, dataChanFreq, dataChanWidth, dataFrame, qrestfreq, freqmin, freqmax,
3398 : phaseCenterToUse))
3399 : throw(AipsError("Failed to determine channelization parameters"));
3400 :
3401 : Bool nonLinearFreq(false);
3402 : String veltype_p=veltype;
3403 : veltype_p.upcase();
3404 : if(veltype_p.contains("OPTICAL") || veltype_p.matches("Z") || veltype_p.contains("BETA") ||
3405 : veltype_p.contains("RELATI") || veltype_p.contains("GAMMA"))
3406 : {
3407 : nonLinearFreq= true;
3408 : }
3409 :
3410 : SpectralCoordinate mySpectral;
3411 : Double stepf;
3412 : if(!nonLinearFreq)
3413 : //TODO: velocity mode default start case (use last channels?)
3414 : {
3415 : Double startf=chanFreq[0];
3416 : //Double stepf=chanFreqStep[0];
3417 : if(chanFreq.nelements()==1)
3418 : {
3419 : stepf=chanFreqStep[0];
3420 : }
3421 : else
3422 : {
3423 : stepf=chanFreq[1]-chanFreq[0];
3424 : }
3425 : Double restf=qrestfreq.getValue("Hz");
3426 : //cerr<<" startf="<<startf<<" stepf="<<stepf<<" refPix="<<refPix<<" restF="<<restf<<endl;
3427 : // once NOFRAME is implemented do this
3428 : if(mode=="cubedata")
3429 : {
3430 : // mySpectral = SpectralCoordinate(freqFrameValid ? MFrequency::Undefined : MFrequency::REST,
3431 : mySpectral = SpectralCoordinate(freqFrame == MFrequency::REST?
3432 : MFrequency::REST : MFrequency::Undefined,
3433 : startf, stepf, refPix, restf);
3434 : }
3435 : else
3436 : {
3437 : mySpectral = SpectralCoordinate(freqFrameValid ? freqFrame : MFrequency::REST,
3438 : startf, stepf, refPix, restf);
3439 : }
3440 : }
3441 : else
3442 : { // nonlinear freq coords - use tabular setting
3443 : // once NOFRAME is implemented do this
3444 : if(mode=="cubedata")
3445 : {
3446 : //mySpectral = SpectralCoordinate(freqFrameValid ? MFrequency::Undefined : MFrequency::REST,
3447 : mySpectral = SpectralCoordinate(freqFrame == MFrequency::REST ?
3448 : MFrequency::REST : MFrequency::Undefined,
3449 : chanFreq, (Double)qrestfreq.getValue("Hz"));
3450 : }
3451 : else
3452 : {
3453 : mySpectral = SpectralCoordinate(freqFrameValid ? freqFrame : MFrequency::REST,
3454 : chanFreq, (Double)qrestfreq.getValue("Hz"));
3455 : }
3456 : }
3457 : //cout << "Rest Freq : " << restFreq << endl;
3458 :
3459 : for(uInt k=1 ; k < restFreq.nelements(); ++k)
3460 : mySpectral.setRestFrequency(restFreq[k].getValue("Hz"));
3461 :
3462 : if ( freqFrameValid ) {
3463 : mySpectral.setReferenceConversion(MFrequency::LSRK,obsEpoch,obsPosition,phaseCenterToUse);
3464 : }
3465 :
3466 : // cout << "RF from coordinate : " << mySpectral.restFrequency() << endl;
3467 :
3468 : ////////////////// Stokes Coordinate
3469 :
3470 : Vector<Int> whichStokes = decideNPolPlanes(stokes);
3471 : if(whichStokes.nelements()==0)
3472 : throw(AipsError("Stokes selection of " + stokes + " is invalid"));
3473 : StokesCoordinate myStokes(whichStokes);
3474 :
3475 : ////////////////// Build Full coordinate system.
3476 :
3477 : CoordinateSystem csys;
3478 : csys.addCoordinate(myRaDec);
3479 : csys.addCoordinate(myStokes);
3480 : csys.addCoordinate(mySpectral);
3481 : csys.setObsInfo(myobsinfo);
3482 :
3483 : //////////////// Set Observatory info, if MS is provided.
3484 : // (remove this section after verified...)
3485 : return csys;
3486 : }
3487 : */
3488 :
3489 14 : MDirection SynthesisParamsImage::getMovingSourceDir(const MeasurementSet& ms, const MEpoch& refEp, const MPosition& obsposition, const MDirection::Types outframe){
3490 14 : MDirection outdir;
3491 14 : String ephemtab(movingSource);
3492 14 : if(movingSource=="TRACKFIELD"){
3493 6 : Int fieldID=MSColumns(ms).fieldId()(0);
3494 6 : ephemtab=Path(MSColumns(ms).field().ephemPath(fieldID)).absoluteName();
3495 : }
3496 14 : casacore::MDirection::Types planetType=MDirection::castType(trackDir.getRef().getType());
3497 14 : if( (! Table::isReadable(ephemtab)) && ( (planetType <= MDirection::N_Types) || (planetType >= MDirection::COMET)))
3498 0 : throw(AipsError("Does not have a valid ephemeris table or major solar system object defined"));
3499 14 : MeasFrame mframe(refEp, obsposition);
3500 14 : MDirection::Ref outref1(MDirection::AZEL, mframe);
3501 14 : MDirection::Ref outref(outframe, mframe);
3502 14 : MDirection tmpazel;
3503 : // (TT) Switched the order of evaluation of if statement (if ephem table is readable
3504 : // one should use that. MDirection::getType will match MDirection::Types if a string conains and starts with
3505 : // one of the enum names in MDirection::Types. So the table name can be mistaken as a major planets in MDirection::Types
3506 : // if it is evaluated first.
3507 14 : if (Table::isReadable(ephemtab)){
3508 12 : MeasComet mcomet(Path(ephemtab).absoluteName());
3509 12 : mframe.set(mcomet);
3510 12 : tmpazel=MDirection::Convert(MDirection(MDirection::COMET), outref1)();
3511 12 : }
3512 2 : else if (planetType >=MDirection::MERCURY && planetType <MDirection::COMET){
3513 2 : tmpazel=MDirection::Convert(trackDir, outref1)();
3514 : }
3515 14 : outdir=MDirection::Convert(tmpazel, outref)();
3516 :
3517 28 : return outdir;
3518 14 : }
3519 :
3520 942 : Bool SynthesisParamsImage::getImFreq(Vector<Double>& chanFreq, Vector<Double>& chanFreqStep,
3521 : Double& refPix, String& specmode,
3522 : const MEpoch& obsEpoch, const MPosition& obsPosition,
3523 : const Vector<Double>& dataChanFreq,
3524 : const Vector<Double>& dataChanWidth,
3525 : const MFrequency::Types& dataFrame,
3526 : const Quantity& qrestfreq, const Double& freqmin, const Double& freqmax,
3527 : const MDirection& phaseCenter)
3528 : {
3529 :
3530 942 : String inStart, inStep;
3531 942 : specmode = findSpecMode(mode);
3532 942 : String freqframe;
3533 942 : Bool verbose("true"); // verbose logging messages from calcChanFreqs
3534 1884 : LogIO os( LogOrigin("SynthesisParamsImage","getImFreq",WHERE) );
3535 :
3536 942 : refPix=0.0;
3537 942 : Bool descendingfreq(false);
3538 942 : Bool descendingoutfreq(false);
3539 :
3540 942 : if( mode.contains("cube") )
3541 : {
3542 479 : String restfreq=QuantityToString(qrestfreq);
3543 : // use frame from input start or width in MFreaquency or MRadialVelocity
3544 479 : freqframe = qmframe!=""? qmframe: MFrequency::showType(freqFrame);
3545 : // emit warning here if qmframe is used
3546 : //
3547 479 : inStart = start;
3548 479 : inStep = step;
3549 479 : if( specmode=="channel" )
3550 : {
3551 398 : inStart = String::toString(chanStart);
3552 398 : inStep = String::toString(chanStep);
3553 : // negative step -> descending channel indices
3554 398 : if (inStep.contains(casacore::Regex("^-"))) descendingfreq=true;
3555 : // input frame is the data frame
3556 : //freqframe = MFrequency::showType(dataFrame);
3557 : }
3558 81 : else if( specmode=="frequency" )
3559 : {
3560 : //if ( freqStart.getValue("Hz") == 0 && freqStart.getUnit() != "" ) { // default start
3561 : //start = String::toString( freqmin ) + freqStart.getUnit();
3562 : //}
3563 : //else {
3564 : //start = String::toString( freqStart.getValue(freqStart.getUnit()) )+freqStart.getUnit();
3565 : //}
3566 : //step = String::toString( freqStep.getValue(freqStep.getUnit()) )+freqStep.getUnit();
3567 : // negative freq width -> descending freq ordering
3568 49 : if(inStep.contains(casacore::Regex("^-"))) descendingfreq=true;
3569 : }
3570 32 : else if( specmode=="velocity" )
3571 : {
3572 : // if velStart is empty set start to vel of freqmin or freqmax?
3573 : //if ( velStart.getValue(velStart.getUnit()) == 0 && !(velStart.getUnit().contains("m/s")) ) {
3574 : // start = "";
3575 : //}
3576 : //else {
3577 : // start = String::toString( velStart.getValue(velStart.getUnit()) )+velStart.getUnit();
3578 : //}
3579 : //step = String::toString( velStep.getValue(velStep.getUnit()) )+velStep.getUnit();
3580 : // positive velocity width -> descending freq ordering
3581 32 : if (!inStep.contains(casacore::Regex("^-"))) descendingfreq=true;
3582 : }
3583 :
3584 479 : if (inStep=='0') inStep="";
3585 :
3586 479 : MRadialVelocity mSysVel;
3587 479 : Quantity qVel;
3588 : MRadialVelocity::Types mRef;
3589 479 : if(mode!="cubesource")
3590 : {
3591 :
3592 :
3593 474 : if(freqframe=="SOURCE")
3594 : {
3595 : os << LogIO::SEVERE << "freqframe=\"SOURCE\" is only allowed for mode=\"cubesrc\""
3596 0 : << LogIO::EXCEPTION;
3597 0 : return false;
3598 : }
3599 : }
3600 : else // only for cubesrc mode: TODO- check for the ephemeris info.
3601 : {
3602 5 : freqframe=MFrequency::showType(dataFrame);
3603 5 : if(sysvel!="") {
3604 0 : stringToQuantity(sysvel,qVel);
3605 0 : MRadialVelocity::getType(mRef,sysvelframe);
3606 0 : mSysVel=MRadialVelocity(qVel,mRef);
3607 : }
3608 : else // and if no ephemeris info, issue a warning...
3609 5 : { mSysVel=MRadialVelocity();}
3610 : }
3611 : // cubedata mode: input start, step are those of the input data frame
3612 479 : if ( mode=="cubedata" )
3613 : {
3614 2 : freqframe=MFrequency::showType(dataFrame);
3615 2 : freqFrameValid=false; // no conversion for vb.lsrfrequency()
3616 : }
3617 : //if ( mode=="cubedata" ) freqframe=MFrequency::REST;
3618 :
3619 : // *** NOTE ***
3620 : // calcChanFreqs alway returns chanFreq in
3621 : // ascending freq order.
3622 : // for step < 0 calcChanFreqs returns chanFreq that
3623 : // contains start freq. in its last element of the vector.
3624 : //
3625 479 : os << LogIO::DEBUG1<<"mode="<<mode<<" specmode="<<specmode<<" inStart="<<inStart
3626 : <<" inStep="<<inStep<<" restfreq="<<restfreq<<" freqframe="<<freqframe
3627 958 : <<" dataFrame="<<dataFrame <<" veltype="<<veltype<<" nchan="<<nchan
3628 479 : << LogIO::POST;
3629 479 : ostringstream ostr;
3630 479 : ostr << " phaseCenter='" << phaseCenter;
3631 479 : os << String(ostr)<<"' ";
3632 :
3633 : Double dummy; // dummy variable - weightScale is not used here
3634 958 : Bool rst=MSTransformRegridder::calcChanFreqs(os,
3635 : chanFreq,
3636 : chanFreqStep,
3637 : dummy,
3638 : dataChanFreq,
3639 : dataChanWidth,
3640 : phaseCenter,
3641 : dataFrame,
3642 : obsEpoch,
3643 : obsPosition,
3644 : specmode,
3645 : nchan,
3646 : inStart,
3647 : inStep,
3648 : restfreq,
3649 : freqframe,
3650 479 : veltype,
3651 : verbose,
3652 : mSysVel
3653 : );
3654 :
3655 479 : if( nchan==-1 )
3656 : {
3657 280 : nchan = chanFreq.nelements();
3658 280 : os << LogIO::DEBUG1 << "Setting nchan to number of selected channels : " << nchan << LogIO::POST;
3659 : }
3660 :
3661 479 : if (!rst) {
3662 : os << LogIO::SEVERE << "calcChanFreqs failed, check input start and width parameters"
3663 1 : << LogIO::EXCEPTION;
3664 0 : return false;
3665 : }
3666 : os << LogIO::DEBUG1
3667 478 : <<"chanFreq 0="<<chanFreq[0]<<" chanFreq last="<<chanFreq[chanFreq.nelements()-1]
3668 956 : << LogIO::POST;
3669 :
3670 478 : if (chanFreq[0]>chanFreq[chanFreq.nelements()-1]) {
3671 14 : descendingoutfreq = true;
3672 : }
3673 :
3674 : //if (descendingfreq && !descendingoutfreq) {
3675 876 : if ((specmode=="channel" && descendingfreq==1)
3676 876 : || (specmode!="channel" && (descendingfreq != descendingoutfreq))) {
3677 : // reverse the freq vector if necessary so the first element can be
3678 : // used to set spectralCoordinates in all the cases.
3679 : //
3680 : // also do for chanFreqStep..
3681 31 : std::vector<Double> stlchanfreq;
3682 31 : chanFreq.tovector(stlchanfreq);
3683 31 : std::reverse(stlchanfreq.begin(),stlchanfreq.end());
3684 31 : chanFreq=Vector<Double>(stlchanfreq);
3685 31 : chanFreqStep=-chanFreqStep;
3686 31 : }
3687 482 : }
3688 463 : else if ( mode=="mfs" ) {
3689 463 : chanFreq.resize(1);
3690 463 : chanFreqStep.resize(1);
3691 : //chanFreqStep[0] = freqmax - freqmin;
3692 463 : Double freqmean = (freqmin + freqmax)/2;
3693 463 : if (refFreq.getValue("Hz")==0) {
3694 407 : chanFreq[0] = freqmean;
3695 407 : refPix = 0.0;
3696 407 : chanFreqStep[0] = freqmax - freqmin;
3697 : }
3698 : else {
3699 56 : chanFreq[0] = refFreq.getValue("Hz");
3700 : // Set the new reffreq to be the refPix (CAS-9518)
3701 56 : refPix = 0.0; // (refFreq.getValue("Hz") - freqmean)/chanFreqStep[0];
3702 : // A larger bandwidth to compensate for the shifted reffreq (CAS-9518)
3703 56 : chanFreqStep[0] = freqmax - freqmin + 2*fabs(chanFreq[0] - freqmean);
3704 : }
3705 :
3706 463 : if( nchan==-1 ) nchan=1;
3707 463 : if( qrestfreq.getValue("Hz")==0.0 ) {
3708 46 : restFreq.resize(1);
3709 46 : restFreq[0] = Quantity(freqmean,"Hz");
3710 : }
3711 : }
3712 : else {
3713 : // unrecognized mode, error
3714 0 : os << LogIO::SEVERE << "mode="<<mode<<" is unrecognized."
3715 0 : << LogIO::EXCEPTION;
3716 0 : return false;
3717 : }
3718 941 : return true;
3719 :
3720 945 : }//getImFreq
3721 : /////////////////////////
3722 943 : Double SynthesisParamsImage::getCubeImageStartFreq(){
3723 943 : Double inStartFreq=-1.0;
3724 943 : String checkspecmode("");
3725 943 : if(mode.contains("cube")) {
3726 480 : checkspecmode = findSpecMode(mode);
3727 : }
3728 943 : if(checkspecmode!="") {
3729 480 : MFrequency::Types mfreqframe = frame!="" ? MFrequency::typeFromString(frame):MFrequency::LSRK;
3730 480 : if(checkspecmode=="channel") {
3731 399 : inStartFreq=-1.0;
3732 : }
3733 : else {
3734 81 : if(checkspecmode=="frequency") {
3735 49 : inStartFreq = freqStart.get("Hz").getValue();
3736 : }
3737 32 : else if(checkspecmode=="velocity") {
3738 : MDoppler::Types DopType;
3739 32 : MDoppler::getType(DopType, veltype);
3740 32 : MDoppler mdop(velStart,DopType);
3741 32 : Quantity qrestfreq = restFreq.nelements() >0 ? restFreq[0]: Quantity(0.0, "Hz");
3742 32 : inStartFreq = MFrequency::fromDoppler(mdop, qrestfreq.getValue(Unit("Hz")), mfreqframe).getValue();
3743 32 : }
3744 : }
3745 : }
3746 :
3747 943 : return inStartFreq;
3748 :
3749 943 : }
3750 :
3751 1512 : String SynthesisParamsImage::findSpecMode(const String& mode) const
3752 : {
3753 1512 : String specmode;
3754 1512 : specmode="channel";
3755 1512 : if ( mode.contains("cube") ) {
3756 : // if velstart or velstep is defined -> specmode='vel'
3757 : // else if freqstart or freqstep is defined -> specmode='freq'
3758 : // velocity: assume unset if velStart => 0.0 with no unit
3759 : // assume unset if velStep => 0.0 with/without unit
3760 2054 : if ( !(velStart.getValue()==0.0 && velStart.getUnit()=="" ) ||
3761 1005 : !( velStep.getValue()==0.0)) {
3762 64 : specmode="velocity";
3763 : }
3764 1875 : else if ( !(freqStart.getValue()==0.0 && freqStart.getUnit()=="") ||
3765 890 : !(freqStep.getValue()==0.0)) {
3766 103 : specmode="frequency";
3767 : }
3768 : }
3769 1512 : return specmode;
3770 0 : }
3771 :
3772 :
3773 2824 : Vector<Int> SynthesisParamsImage::decideNPolPlanes(const String& stokes) const
3774 : {
3775 2824 : Vector<Int> whichStokes(0);
3776 3295 : if(stokes=="I" || stokes=="Q" || stokes=="U" || stokes=="V" ||
3777 567 : stokes=="RR" ||stokes=="LL" ||
3778 3295 : stokes=="XX" || stokes=="YY" ) {
3779 2641 : whichStokes.resize(1);
3780 2641 : whichStokes(0)=Stokes::type(stokes);
3781 : }
3782 519 : else if(stokes=="IV" || stokes=="IQ" ||
3783 498 : stokes=="RRLL" || stokes=="XXYY" ||
3784 513 : stokes=="QU" || stokes=="UV"){
3785 33 : whichStokes.resize(2);
3786 :
3787 33 : if(stokes=="IV"){ whichStokes[0]=Stokes::I; whichStokes[1]=Stokes::V;}
3788 18 : else if(stokes=="IQ"){whichStokes[0]=Stokes::I; whichStokes[1]=Stokes::Q;}
3789 18 : else if(stokes=="RRLL"){whichStokes[0]=Stokes::RR; whichStokes[1]=Stokes::LL;}
3790 18 : else if(stokes=="XXYY"){whichStokes[0]=Stokes::XX; whichStokes[1]=Stokes::YY; }
3791 12 : else if(stokes=="QU"){whichStokes[0]=Stokes::Q; whichStokes[1]=Stokes::U; }
3792 0 : else if(stokes=="UV"){ whichStokes[0]=Stokes::U; whichStokes[1]=Stokes::V; }
3793 :
3794 : }
3795 :
3796 150 : else if(stokes=="IQU" || stokes=="IUV") {
3797 0 : whichStokes.resize(3);
3798 0 : if(stokes=="IUV")
3799 0 : {whichStokes[0]=Stokes::I; whichStokes[1]=Stokes::U; whichStokes[2]=Stokes::V;}
3800 : else
3801 0 : {whichStokes[0]=Stokes::I; whichStokes[1]=Stokes::Q; whichStokes[2]=Stokes::U;}
3802 : }
3803 150 : else if(stokes=="IQUV"){
3804 150 : whichStokes.resize(4);
3805 150 : whichStokes(0)=Stokes::I; whichStokes(1)=Stokes::Q;
3806 150 : whichStokes(2)=Stokes::U; whichStokes(3)=Stokes::V;
3807 : }
3808 :
3809 2824 : return whichStokes;
3810 0 : }// decidenpolplanes
3811 :
3812 1883 : IPosition SynthesisParamsImage::shp() const
3813 : {
3814 1883 : uInt nStokes = ( decideNPolPlanes(stokes) ).nelements();
3815 :
3816 1883 : if( imsize[0]<=0 || imsize[1]<=0 || nStokes<=0 || nchan<=0 )
3817 : {
3818 1 : throw(AipsError("Internal Error : Image shape is invalid : [" + String::toString(imsize[0]) + "," + String::toString(imsize[1]) + "," + String::toString(nStokes) + "," + String::toString(nchan) + "]" ));
3819 : }
3820 :
3821 3764 : return IPosition( 4, imsize[0], imsize[1], nStokes, nchan );
3822 : }
3823 :
3824 941 : Record SynthesisParamsImage::getcsys() const
3825 : {
3826 941 : return csysRecord;
3827 : }
3828 :
3829 0 : Record SynthesisParamsImage::updateParams(const Record& impar)
3830 : {
3831 0 : Record newimpar( impar );
3832 0 : if ( impar.isDefined("csys") )
3833 : {
3834 0 : Vector<Int> newimsize(2);
3835 0 : newimsize[0] = imshape[0];
3836 0 : newimsize[1] = imshape[1];
3837 0 : newimpar.define("imsize", newimsize);
3838 0 : if ( newimpar.isDefined("direction0") )
3839 : {
3840 0 : Record dirRec = newimpar.subRecord("direction0");
3841 0 : Vector<Double> cdelta = dirRec.asArrayDouble("cdelt");
3842 0 : Vector<String> cells(2);
3843 0 : cells[0] = String::toString(-1*cdelta[0]) + "rad";
3844 0 : cells[1] = String::toString(-1*cdelta[1]) + "rad";
3845 0 : newimpar.define("cell", cells );
3846 0 : }
3847 0 : if ( newimpar.isDefined("stokes1") )
3848 : {
3849 0 : Record stokesRec = newimpar.subRecord("stokes1");
3850 0 : Vector<String> stokesvecs = stokesRec.asArrayString("stokes");
3851 0 : String stokesStr;
3852 0 : for (uInt j = 0; j < stokesvecs.nelements(); j++)
3853 : {
3854 0 : stokesStr+=stokesvecs[j];
3855 : }
3856 0 : }
3857 0 : if ( newimpar.isDefined("nchan") )
3858 : {
3859 0 : newimpar.define("nchan",imshape[2]);
3860 : }
3861 0 : if ( newimpar.isDefined("spectral2") )
3862 : {
3863 0 : Record specRec = newimpar.subRecord("spectral2");
3864 0 : if ( specRec.isDefined("restfreqs") )
3865 : {
3866 0 : Vector<Double> restfs = specRec.asArrayDouble("restfreqs");
3867 0 : Vector<String> restfstrs(restfs.nelements());
3868 0 : for(uInt restf=0; restf<restfs.nelements(); restf++){restfstrs[restf] = String::toString(restfs[restf]) + "Hz";}
3869 0 : newimpar.define("restfreq",restfstrs);
3870 0 : }
3871 : //reffreq?
3872 : //outframe
3873 : //sysvel
3874 : //sysvelframe
3875 0 : }
3876 0 : }
3877 0 : return newimpar;
3878 0 : }
3879 :
3880 : /////////////////////// Grid/FTMachine Parameters
3881 :
3882 5545 : SynthesisParamsGrid::SynthesisParamsGrid():SynthesisParams()
3883 : {
3884 5545 : setDefaults();
3885 5545 : }
3886 :
3887 5544 : SynthesisParamsGrid::~SynthesisParamsGrid()
3888 : {
3889 5544 : }
3890 :
3891 :
3892 1845 : void SynthesisParamsGrid::fromRecord(const Record &inrec)
3893 : {
3894 1845 : setDefaults();
3895 :
3896 1845 : String err("");
3897 :
3898 : try {
3899 1845 : err += readVal( inrec, String("imagename"), imageName );
3900 :
3901 : // FTMachine parameters
3902 1845 : err += readVal( inrec, String("gridder"), gridder );
3903 1845 : err += readVal( inrec, String("padding"), padding );
3904 1845 : err += readVal( inrec, String("useautocorr"), useAutoCorr );
3905 1845 : err += readVal( inrec, String("usedoubleprec"), useDoublePrec );
3906 1845 : err += readVal( inrec, String("wprojplanes"), wprojplanes );
3907 1845 : err += readVal( inrec, String("convfunc"), convFunc );
3908 :
3909 1845 : err += readVal( inrec, String("vptable"), vpTable );
3910 :
3911 :
3912 :
3913 : // convert 'gridder' to 'ftmachine' and 'mtype'
3914 1845 : ftmachine = "gridft";
3915 1845 : mType = "default";
3916 1845 : if (gridder=="ft" || gridder=="gridft" || gridder=="standard") {
3917 1268 : ftmachine = "gridft";
3918 : }
3919 623 : else if ( (gridder=="widefield" || gridder=="wproject" || gridder=="wprojectft" ) &&
3920 46 : (wprojplanes>1 || wprojplanes==-1) ) {
3921 45 : ftmachine = "wprojectft";
3922 : }
3923 : //facetting alone use gridft
3924 532 : else if( (gridder=="widefield" || gridder=="wproject" || gridder=="wprojectft" ) && (wprojplanes==1))
3925 1 : {ftmachine=="gridft";}
3926 :
3927 531 : else if (gridder=="ftmosaic" || gridder=="mosaicft" || gridder=="mosaic" ) {
3928 222 : ftmachine = "mosaicft";
3929 : }
3930 :
3931 309 : else if (gridder=="imagemosaic") {
3932 0 : mType = "imagemosaic";
3933 0 : if (wprojplanes>1 || wprojplanes==-1) {
3934 0 : ftmachine = "wprojectft";
3935 : }
3936 : }
3937 :
3938 309 : else if (gridder=="awproject" || gridder=="awprojectft" || gridder=="awp") {
3939 93 : ftmachine = "awprojectft";
3940 : }
3941 :
3942 216 : else if (gridder=="singledish") {
3943 :
3944 160 : ftmachine = "sd";
3945 : }
3946 : else{
3947 56 : ftmachine=gridder;
3948 56 : ftmachine.downcase();
3949 :
3950 : }
3951 :
3952 1845 : String deconvolver;
3953 1845 : err += readVal( inrec, String("deconvolver"), deconvolver );
3954 1845 : if (deconvolver=="mtmfs") {
3955 122 : mType = "multiterm"; // Takes precedence over imagemosaic
3956 : }
3957 :
3958 : // facets
3959 1845 : err += readVal( inrec, String("facets"), facets );
3960 : // chanchunks
3961 1845 : err += readVal( inrec, String("chanchunks"), chanchunks );
3962 :
3963 : // Spectral interpolation
3964 1845 : err += readVal( inrec, String("interpolation"), interpolation ); // not used in SI yet...
3965 : // Track moving source ?
3966 1845 : err += readVal( inrec, String("distance"), distance );
3967 1845 : err += readVal( inrec, String("tracksource"), trackSource );
3968 1845 : err += readVal( inrec, String("trackdir"), trackDir );
3969 :
3970 : // The extra params for WB-AWP
3971 1845 : err += readVal( inrec, String("aterm"), aTermOn );
3972 1845 : err += readVal( inrec, String("psterm"), psTermOn );
3973 1845 : err += readVal( inrec, String("mterm"), mTermOn );
3974 1845 : err += readVal( inrec, String("wbawp"), wbAWP );
3975 1845 : err += readVal( inrec, String("cfcache"), cfCache );
3976 1845 : err += readVal( inrec, String("usepointing"), usePointing );
3977 1845 : err += readVal( inrec, String("pointingoffsetsigdev"), pointingOffsetSigDev );
3978 1845 : err += readVal( inrec, String("dopbcorr"), doPBCorr );
3979 1845 : err += readVal( inrec, String("conjbeams"), conjBeams );
3980 1845 : err += readVal( inrec, String("computepastep"), computePAStep );
3981 1845 : err += readVal( inrec, String("rotatepastep"), rotatePAStep );
3982 :
3983 : // The extra params for single-dish
3984 1845 : err += readVal( inrec, String("pointingcolumntouse"), pointingDirCol );
3985 1845 : err += readVal( inrec, String("convertfirst"), convertFirst );
3986 1845 : err += readVal( inrec, String("skypolthreshold"), skyPosThreshold );
3987 1845 : err += readVal( inrec, String("convsupport"), convSupport );
3988 1845 : err += readVal( inrec, String("truncate"), truncateSize );
3989 1845 : err += readVal( inrec, String("gwidth"), gwidth );
3990 1845 : err += readVal( inrec, String("jwidth"), jwidth );
3991 1845 : err += readVal( inrec, String("minweight"), minWeight );
3992 1845 : err += readVal( inrec, String("clipminmax"), clipMinMax );
3993 :
3994 : // Single or MultiTerm mapper : read in 'deconvolver' and set mType here.
3995 : // err += readVal( inrec, String("mtype"), mType );
3996 :
3997 1845 : if (ftmachine=="awprojectft" && cfCache=="") {
3998 0 : cfCache = imageName + ".cf";
3999 : }
4000 :
4001 1845 : if ( ftmachine=="awprojectft" &&
4002 1879 : usePointing==True &&
4003 34 : pointingOffsetSigDev.nelements() != 2 ) {
4004 : // Set the default to a large value so that it behaves like CASA 5.6's usepointing=True.
4005 8 : pointingOffsetSigDev.resize(2);
4006 8 : pointingOffsetSigDev[0] = 600.0;
4007 8 : pointingOffsetSigDev[1] = 600.0;
4008 : }
4009 :
4010 1845 : err += verify();
4011 :
4012 1845 : } catch(AipsError &x) {
4013 0 : err = err + x.getMesg() + "\n";
4014 0 : }
4015 :
4016 1845 : if (err.length()>0) {
4017 0 : throw(AipsError("Invalid Gridding/FTM Parameter set: " + err));
4018 : }
4019 :
4020 1845 : }
4021 :
4022 1845 : String SynthesisParamsGrid::verify() const
4023 : {
4024 1845 : String err;
4025 :
4026 : // Check for valid FTMachine type.
4027 : // Valid other params per FTM type, etc... ( check about nterms>1 )
4028 :
4029 :
4030 :
4031 1845 : if ( imageName == "" ) {
4032 0 : err += "Please supply an image name\n";
4033 : }
4034 :
4035 1107 : if( (ftmachine != "gridft") && (ftmachine != "wprojectft") &&
4036 2845 : (ftmachine != "mosaicft") && (ftmachine.at(0,3) != "awp") &&
4037 2581 : (ftmachine != "mawprojectft") &&
4038 160 : (ftmachine != "sd"))
4039 : {
4040 : err += "Invalid ftmachine name. Must be one of"
4041 : " 'gridft', 'wprojectft',"
4042 : " 'mosaicft', 'awprojectft',"
4043 : " 'mawpojectft', 'protoft',"
4044 0 : " 'sd'\n";
4045 : }
4046 :
4047 :
4048 3783 : if ( ( ftmachine == "mosaicft" and mType == "imagemosaic" ) or
4049 1938 : ( ftmachine == "awprojectft" and mType == "imagemosaic" ) ) {
4050 0 : err += "Cannot use " + ftmachine + " with " + mType +
4051 : " because it is a redundant choice for mosaicing."
4052 : " In the future, we may support the combination"
4053 : " to signal the use of single-pointing sized image grids"
4054 : " during gridding and iFT,"
4055 : " and only accumulating it on the large mosaic image."
4056 : " For now, please set"
4057 : " either mappertype='default' to get mosaic gridding"
4058 0 : " or ftmachine='ft' or 'wprojectft' to get image domain mosaics.\n";
4059 : }
4060 :
4061 1845 : if ( facets < 1 ) {
4062 0 : err += "Must have at least 1 facet\n";
4063 : }
4064 :
4065 : //if( chanchunks < 1 )
4066 : // {err += "Must have at least 1 chanchunk\n"; }
4067 1845 : if ( facets > 1 and chanchunks > 1 ) {
4068 : err += "The combination of facetted imaging"
4069 : " with channel chunking is not yet supported."
4070 0 : " Please choose only one or the other for now.\n";
4071 : }
4072 :
4073 1845 : if ( ftmachine == "wproject" and ( wprojplanes == 0 or wprojplanes == 1 ) ) {
4074 : err += "The wproject gridder must be accompanied with"
4075 0 : " wprojplanes>1 or wprojplanes=-1\n";
4076 : }
4077 :
4078 1845 : if ( ftmachine == "awprojectft" and facets > 1 ) {
4079 : err += "The awprojectft gridder supports A- and W-Projection."
4080 : " Instead of using facets>1 to deal with the W-term,"
4081 : " please set the number of wprojplanes to a value > 1"
4082 0 : " to trigger the combined AW-Projection algorithm. \n";
4083 : // Also, the way the AWP cfcache is managed,
4084 : // even if all facets share a common one so that they reuse convolution functions,
4085 : // the first facet's gridder writes out the avgPB
4086 : // and all others see that it's there and don't compute their own.
4087 : // As a result, the code will run,
4088 : // but the first facet's weight image will be duplicated for all facets.
4089 : // If needed, this must be fixed in the way the AWP gridder manages its cfcache.
4090 : // But, since the AWP gridder supports joint A and W projection,
4091 : // facet support may never be needed in the first place...
4092 : }
4093 :
4094 1845 : if ( ftmachine == "awprojectft" and wprojplanes == -1 ) {
4095 : err += "The awprojectft gridder does not support wprojplanes=-1"
4096 0 : " for automatic calculation. Please pick a value >1\n";
4097 : }
4098 :
4099 1845 : if ( ftmachine == "mosaicft" and facets > 1 ) {
4100 : err += "The combination of mosaicft gridding"
4101 : " with multiple facets is not supported."
4102 : " Please use the awprojectft gridder instead,"
4103 0 : " and set wprojplanes to a value > 1 to trigger AW-Projection.\n";
4104 : }
4105 :
4106 1879 : if ( ftmachine == "awprojectft" and usePointing == True and
4107 34 : pointingOffsetSigDev.nelements() != 2 ) {
4108 : err += "The pointingoffsetsigdev parameter must be"
4109 : " a two-element vector of doubles in order to be used with usepointing=True"
4110 0 : " and the AWProject gridder. Setting it to the default of \n";
4111 : }
4112 :
4113 : // Single-dish parameters check
4114 1845 : if ( ftmachine == "sd" ) {
4115 320 : if ( convertFirst != "always" and
4116 320 : convertFirst != "never" and
4117 0 : convertFirst != "auto" ) {
4118 0 : err += "convertfirst parameter: illegal value: '" + convertFirst + "'."
4119 0 : " Allowed values: 'always', 'never', 'auto'.\n";
4120 : }
4121 : }
4122 :
4123 1845 : return err;
4124 0 : }
4125 :
4126 7390 : void SynthesisParamsGrid::setDefaults()
4127 : {
4128 7390 : imageName="";
4129 : // FTMachine parameters
4130 : //ftmachine="GridFT";
4131 7390 : ftmachine="gridft";
4132 7390 : gridder=ftmachine;
4133 7390 : padding=1.2;
4134 7390 : useAutoCorr=false;
4135 7390 : useDoublePrec=true;
4136 7390 : wprojplanes=1;
4137 7390 : convFunc="SF";
4138 7390 : vpTable="";
4139 :
4140 : // facets
4141 7390 : facets=1;
4142 :
4143 : // chanchunks
4144 7390 : chanchunks=1;
4145 :
4146 : // Spectral Axis interpolation
4147 7390 : interpolation=String("nearest");
4148 :
4149 : //mosaic use pointing
4150 7390 : usePointing=false;
4151 : // Moving phase center ?
4152 7390 : distance=Quantity(0,"m");
4153 7390 : trackSource=false;
4154 7390 : trackDir=MDirection(Quantity(0.0, "deg"), Quantity(90.0, "deg"));
4155 :
4156 : // The extra params for WB-AWP
4157 7390 : aTermOn = true;
4158 7390 : psTermOn = true;
4159 7390 : mTermOn = false;
4160 7390 : wbAWP = true;
4161 7390 : cfCache = "";
4162 7390 : usePointing = false;
4163 7390 : pointingOffsetSigDev.resize(0);
4164 : // pointingOffsetSigDev.set(30.0);
4165 7390 : doPBCorr = true;
4166 7390 : conjBeams = true;
4167 7390 : computePAStep=360.0;
4168 7390 : rotatePAStep=5.0;
4169 :
4170 : // extra params for single-dish
4171 7390 : pointingDirCol = "";
4172 7390 : convertFirst = "never";
4173 7390 : skyPosThreshold = 0.0;
4174 7390 : convSupport = -1;
4175 7390 : truncateSize = Quantity(-1.0);
4176 7390 : gwidth = Quantity(-1.0);
4177 7390 : jwidth = Quantity(-1.0);
4178 7390 : minWeight = 0.0;
4179 7390 : clipMinMax = False;
4180 :
4181 : // Mapper type
4182 7390 : mType = String("default");
4183 :
4184 7390 : }
4185 :
4186 899 : Record SynthesisParamsGrid::toRecord() const
4187 : {
4188 899 : Record gridpar;
4189 :
4190 899 : gridpar.define("imagename", imageName);
4191 : // FTMachine params
4192 899 : gridpar.define("padding", padding);
4193 899 : gridpar.define("useautocorr",useAutoCorr );
4194 899 : gridpar.define("usedoubleprec", useDoublePrec);
4195 899 : gridpar.define("wprojplanes", wprojplanes);
4196 899 : gridpar.define("convfunc", convFunc);
4197 899 : gridpar.define("vptable", vpTable);
4198 :
4199 899 : gridpar.define("facets", facets);
4200 899 : gridpar.define("chanchunks", chanchunks);
4201 :
4202 899 : gridpar.define("interpolation",interpolation);
4203 :
4204 899 : gridpar.define("distance", QuantityToString(distance));
4205 899 : gridpar.define("tracksource", trackSource);
4206 899 : gridpar.define("trackdir", MDirectionToString( trackDir ));
4207 :
4208 899 : gridpar.define("aterm",aTermOn );
4209 899 : gridpar.define("psterm",psTermOn );
4210 899 : gridpar.define("mterm",mTermOn );
4211 899 : gridpar.define("wbawp", wbAWP);
4212 899 : gridpar.define("cfcache", cfCache);
4213 899 : gridpar.define("usepointing",usePointing );
4214 899 : gridpar.define("pointingoffsetsigdev", pointingOffsetSigDev);
4215 899 : gridpar.define("dopbcorr", doPBCorr);
4216 899 : gridpar.define("conjbeams",conjBeams );
4217 899 : gridpar.define("computepastep", computePAStep);
4218 899 : gridpar.define("rotatepastep", rotatePAStep);
4219 :
4220 899 : gridpar.define("pointingcolumntouse", pointingDirCol );
4221 899 : gridpar.define("convertfirst", convertFirst );
4222 899 : gridpar.define("skyposthreshold", skyPosThreshold );
4223 899 : gridpar.define("convsupport", convSupport );
4224 899 : gridpar.define("truncate", QuantityToString(truncateSize) );
4225 899 : gridpar.define("gwidth", QuantityToString(gwidth) );
4226 899 : gridpar.define("jwidth", QuantityToString(jwidth) );
4227 899 : gridpar.define("minweight", minWeight );
4228 899 : gridpar.define("clipminmax", clipMinMax );
4229 :
4230 899 : if( mType=="multiterm") gridpar.define("deconvolver","mtmfs");
4231 : /// else gridpar.define("deconvolver","singleterm");
4232 :
4233 899 : if( mType=="imagemosaic") gridpar.define("gridder","imagemosaic");
4234 899 : else gridpar.define("gridder", gridder);
4235 :
4236 : // gridpar.define("mtype", mType);
4237 :
4238 899 : return gridpar;
4239 0 : }
4240 :
4241 :
4242 :
4243 : ///////////////////////////////////////////////////////////////////////////////////////////////////////////
4244 :
4245 : /////////////////////// Deconvolver Parameters
4246 :
4247 2522 : SynthesisParamsDeconv::SynthesisParamsDeconv():SynthesisParams()
4248 : {
4249 2522 : setDefaults();
4250 2522 : }
4251 :
4252 2522 : SynthesisParamsDeconv::~SynthesisParamsDeconv()
4253 : {
4254 2522 : }
4255 :
4256 :
4257 2518 : void SynthesisParamsDeconv::fromRecord(const Record &inrec)
4258 : {
4259 2518 : setDefaults();
4260 :
4261 2518 : String err("");
4262 :
4263 : try
4264 : {
4265 :
4266 2518 : err += readVal( inrec, String("imagename"), imageName );
4267 2518 : err += readVal( inrec, String("deconvolver"), algorithm );
4268 :
4269 :
4270 : //err += readVal( inrec, String("startmodel"), startModel );
4271 : // startmodel parsing copied from SynthesisParamsImage. Clean this up !!!
4272 2518 : if( inrec.isDefined("startmodel") )
4273 : {
4274 2518 : if( inrec.dataType("startmodel")==TpString )
4275 : {
4276 836 : String onemodel;
4277 836 : err += readVal( inrec, String("startmodel"), onemodel );
4278 836 : if( onemodel.length()>0 )
4279 : {
4280 22 : startModel.resize(1);
4281 22 : startModel[0] = onemodel;
4282 : }
4283 814 : else {startModel.resize();}
4284 836 : }
4285 3366 : else if( inrec.dataType("startmodel")==TpArrayString ||
4286 1684 : inrec.dataType("startmodel")==TpArrayBool)
4287 : {
4288 1682 : err += readVal( inrec, String("startmodel"), startModel );
4289 : }
4290 : else {
4291 0 : err += String("startmodel must be either a string(singleterm) or a list of strings(multiterm)\n");
4292 : }
4293 : }
4294 : //------------------------
4295 :
4296 2518 : err += readVal( inrec, String("id"), deconvolverId );
4297 2518 : err += readVal( inrec, String("nterms"), nTaylorTerms );
4298 :
4299 2518 : err += readVal( inrec, String("scales"), scales );
4300 2518 : err += readVal( inrec, String("scalebias"), scalebias );
4301 :
4302 2518 : err += readVal( inrec, String("usemask"), maskType );
4303 2518 : if( maskType=="auto-thresh" )
4304 : {
4305 0 : autoMaskAlgorithm = "thresh";
4306 : }
4307 2518 : else if( maskType=="auto-thesh2" )
4308 : {
4309 0 : autoMaskAlgorithm = "thresh2";
4310 : }
4311 2518 : else if( maskType=="auto-onebox" )
4312 : {
4313 0 : autoMaskAlgorithm = "onebox";
4314 : }
4315 2518 : else if( maskType=="user" || maskType=="pb" )
4316 : {
4317 2411 : autoMaskAlgorithm = "";
4318 : }
4319 :
4320 :
4321 2518 : if( inrec.isDefined("mask") )
4322 : {
4323 2518 : if( inrec.dataType("mask")==TpString )
4324 : {
4325 1964 : err+= readVal( inrec, String("mask"), maskString );
4326 : }
4327 554 : else if( inrec.dataType("mask")==TpArrayString )
4328 : {
4329 552 : err+= readVal( inrec, String("mask"), maskList );
4330 : }
4331 : }
4332 :
4333 2518 : if( inrec.isDefined("pbmask") )
4334 : {
4335 2518 : err += readVal( inrec, String("pbmask"), pbMask );
4336 : }
4337 2518 : if( inrec.isDefined("maskthreshold") )
4338 : {
4339 2518 : if( inrec.dataType("maskthreshold")==TpString )
4340 : {
4341 2518 : err += readVal( inrec, String("maskthreshold"), maskThreshold );
4342 : //deal with the case a string is a float value without unit
4343 2518 : Quantity testThresholdString;
4344 2518 : Quantity::read(testThresholdString,maskThreshold);
4345 2518 : if( testThresholdString.getUnit()=="" )
4346 : {
4347 2518 : if(testThresholdString.getValue()<1.0)
4348 : {
4349 2518 : fracOfPeak = testThresholdString.getValue();
4350 2518 : maskThreshold=String("");
4351 : }
4352 : }
4353 2518 : }
4354 0 : else if( inrec.dataType("maskthreshold")==TpFloat || inrec.dataType("maskthreshold")==TpDouble )
4355 : {
4356 :
4357 0 : err += readVal( inrec, String("maskthreshold"), fracOfPeak );
4358 0 : if( fracOfPeak >=1.0 )
4359 : {
4360 : // maskthreshold is sigma ( * rms = threshold)
4361 : //
4362 0 : maskThreshold=String::toString(fracOfPeak);
4363 0 : fracOfPeak=0.0;
4364 : }
4365 : }
4366 : else
4367 : {
4368 0 : err += "maskthreshold must be a string, float, or double\n";
4369 : }
4370 : }
4371 2518 : if( inrec.isDefined("maskresolution") )
4372 : {
4373 2518 : if( inrec.dataType("maskresolution")==TpString )
4374 : {
4375 2518 : err += readVal(inrec, String("maskresolution"), maskResolution );
4376 : //deal with the case a string is a float value without unit
4377 2518 : Quantity testResolutionString;
4378 2518 : Quantity::read(testResolutionString,maskResolution);
4379 2518 : if( testResolutionString.getUnit()=="" )
4380 : {
4381 2518 : maskResByBeam = testResolutionString.getValue();
4382 2518 : maskResolution=String("");
4383 : }
4384 2518 : }
4385 0 : else if( inrec.dataType("maskresolution")==TpFloat || inrec.dataType("maskresolution")==TpDouble )
4386 : {
4387 :
4388 0 : err += readVal( inrec, String("maskresolution"), maskResByBeam );
4389 : }
4390 : else
4391 : {
4392 0 : err += "maskresolution must be a string, float, or double\n";
4393 : }
4394 : }
4395 :
4396 :
4397 2518 : if( inrec.isDefined("nmask") )
4398 : {
4399 2518 : if( inrec.dataType("nmask")==TpInt )
4400 : {
4401 2518 : err+= readVal(inrec, String("nmask"), nMask );
4402 : }
4403 : else
4404 : {
4405 0 : err+= "nmask must be an integer\n";
4406 : }
4407 : }
4408 2518 : if( inrec.isDefined("autoadjust") )
4409 : {
4410 1673 : if( inrec.dataType("autoadjust")==TpBool )
4411 : {
4412 1673 : err+= readVal(inrec, String("autoadjust"), autoAdjust );
4413 : }
4414 : else
4415 : {
4416 0 : err+= "autoadjust must be a bool\n";
4417 : }
4418 : }
4419 : //param for the Asp-Clean to trigger Hogbom Clean
4420 2518 : if (inrec.isDefined("fusedthreshold"))
4421 : {
4422 2518 : if (inrec.dataType("fusedthreshold") == TpFloat || inrec.dataType("fusedthreshold") == TpDouble)
4423 2518 : err += readVal(inrec, String("fusedthreshold"), fusedThreshold);
4424 : else
4425 0 : err += "fusedthreshold must be a float or double";
4426 : }
4427 2518 : if (inrec.isDefined("specmode"))
4428 : {
4429 2518 : if(inrec.dataType("specmode") == TpString)
4430 2518 : err += readVal(inrec, String("specmode"), specmode);
4431 : else
4432 0 : err += "specmode must be a string";
4433 : }
4434 : //largest scale size for the Asp-Clean to overwrite the default
4435 2518 : if (inrec.isDefined("largestscale"))
4436 : {
4437 2518 : if (inrec.dataType("largestscale") == TpInt)
4438 2518 : err += readVal(inrec, String("largestscale"), largestscale);
4439 : else
4440 0 : err += "largestscale must be an integer";
4441 : }
4442 : //params for the new automasking algorithm
4443 2518 : if( inrec.isDefined("sidelobethreshold"))
4444 : {
4445 2518 : if(inrec.dataType("sidelobethreshold")==TpFloat || inrec.dataType("sidelobethreshold")==TpDouble )
4446 : {
4447 2518 : err+= readVal(inrec, String("sidelobethreshold"), sidelobeThreshold );
4448 : }
4449 : else
4450 : {
4451 0 : err+= "sidelobethreshold must be a float or double";
4452 : }
4453 : }
4454 :
4455 2518 : if( inrec.isDefined("noisethreshold"))
4456 : {
4457 2518 : if(inrec.dataType("noisethreshold")==TpFloat || inrec.dataType("noisethreshold")==TpDouble )
4458 : {
4459 2518 : err+= readVal(inrec, String("noisethreshold"), noiseThreshold );
4460 : }
4461 : else
4462 : {
4463 0 : err+= "noisethreshold must be a float or double";
4464 : }
4465 : }
4466 2518 : if( inrec.isDefined("lownoisethreshold"))
4467 : {
4468 2518 : if(inrec.dataType("lownoisethreshold")==TpFloat || inrec.dataType("lownoisethreshold")==TpDouble )
4469 : {
4470 2518 : err+= readVal(inrec, String("lownoisethreshold"), lowNoiseThreshold );
4471 : }
4472 : else
4473 : {
4474 0 : err+= "lownoisethreshold must be a float or double";
4475 : }
4476 : }
4477 2518 : if( inrec.isDefined("negativethreshold"))
4478 : {
4479 2518 : if(inrec.dataType("negativethreshold")==TpFloat || inrec.dataType("negativethreshold")==TpDouble )
4480 : {
4481 2518 : err+= readVal(inrec, String("negativethreshold"), negativeThreshold );
4482 : }
4483 : else
4484 : {
4485 0 : err+= "negativethreshold must be a float or double";
4486 : }
4487 : }
4488 2518 : if( inrec.isDefined("smoothfactor"))
4489 : {
4490 2518 : if( inrec.dataType("smoothfactor")==TpFloat || inrec.dataType("smoothfactor")==TpDouble )
4491 : {
4492 2518 : err+= readVal(inrec, String("smoothfactor"), smoothFactor );
4493 : }
4494 : else
4495 : {
4496 0 : err+= "smoothfactor must be a float or double";
4497 : }
4498 : }
4499 2518 : if( inrec.isDefined("minbeamfrac"))
4500 : {
4501 2518 : if( inrec.dataType("minbeamfrac")==TpFloat || inrec.dataType("minbeamfrac")==TpDouble )
4502 : {
4503 2518 : err+= readVal(inrec, String("minbeamfrac"), minBeamFrac );
4504 : }
4505 : else
4506 : {
4507 0 : if (inrec.dataType("minbeamfrac")==TpInt) {
4508 0 : cerr<<"minbeamfrac is int"<<endl;
4509 : }
4510 0 : if (inrec.dataType("minbeamfrac")==TpString) {
4511 0 : cerr<<"minbeamfrac is String"<<endl;
4512 : }
4513 0 : err+= "minbeamfrac must be a float or double";
4514 : }
4515 : }
4516 2518 : if( inrec.isDefined("cutthreshold"))
4517 : {
4518 2518 : if( inrec.dataType("cutthreshold")==TpFloat || inrec.dataType("cutthreshold")==TpDouble )
4519 : {
4520 2518 : err+= readVal(inrec, String("cutthreshold"), cutThreshold );
4521 : }
4522 : else {
4523 0 : err+= "cutthreshold must be a float or double";
4524 : }
4525 : }
4526 2518 : if( inrec.isDefined("growiterations"))
4527 : {
4528 2518 : if (inrec.dataType("growiterations")==TpInt) {
4529 2518 : err+= readVal(inrec, String("growiterations"), growIterations );
4530 : }
4531 : else {
4532 0 : err+= "growiterations must be an integer\n";
4533 : }
4534 : }
4535 2518 : if( inrec.isDefined("dogrowprune"))
4536 : {
4537 2518 : if (inrec.dataType("dogrowprune")==TpBool) {
4538 2518 : err+= readVal(inrec, String("dogrowprune"), doGrowPrune );
4539 : }
4540 : else {
4541 0 : err+= "dogrowprune must be a bool\n";
4542 : }
4543 : }
4544 2518 : if( inrec.isDefined("minpercentchange"))
4545 : {
4546 2518 : if (inrec.dataType("minpercentchange")==TpFloat || inrec.dataType("minpercentchange")==TpDouble ) {
4547 2518 : err+= readVal(inrec, String("minpercentchange"), minPercentChange );
4548 : }
4549 : else {
4550 0 : err+= "minpercentchange must be a float or double";
4551 : }
4552 : }
4553 2518 : if( inrec.isDefined("verbose"))
4554 : {
4555 2518 : if (inrec.dataType("verbose")==TpBool ) {
4556 2518 : err+= readVal(inrec, String("verbose"), verbose);
4557 : }
4558 : else {
4559 0 : err+= "verbose must be a bool";
4560 : }
4561 : }
4562 2518 : if( inrec.isDefined("fastnoise"))
4563 : {
4564 2518 : if (inrec.dataType("fastnoise")==TpBool ) {
4565 2518 : err+= readVal(inrec, String("fastnoise"), fastnoise);
4566 : }
4567 : else {
4568 0 : err+= "fastnoise must be a bool";
4569 : }
4570 : }
4571 2518 : if( inrec.isDefined("nsigma") )
4572 : {
4573 2518 : if(inrec.dataType("nsigma")==TpFloat || inrec.dataType("nsigma")==TpDouble ) {
4574 2518 : err+= readVal(inrec, String("nsigma"), nsigma );
4575 : }
4576 0 : else if(inrec.dataType("nsigma")==TpInt)
4577 : {
4578 : int tnsigma;
4579 0 : err+= readVal(inrec, String("nsigma"), tnsigma );
4580 0 : nsigma = float(tnsigma);
4581 : }
4582 : else {
4583 0 : err+= "nsigma must be an int, float or double";
4584 : }
4585 : }
4586 2518 : if( inrec.isDefined("noRequireSumwt") )
4587 : {
4588 1859 : if (inrec.dataType("noRequireSumwt")==TpBool) {
4589 1859 : err+= readVal(inrec, String("noRequireSumwt"), noRequireSumwt);
4590 : }
4591 : else {
4592 0 : err+= "noRequireSumwt must be a bool";
4593 : }
4594 : }
4595 2518 : if( inrec.isDefined("fullsummary") )
4596 : {
4597 2518 : if (inrec.dataType("fullsummary")==TpBool) {
4598 2518 : err+= readVal(inrec, String("fullsummary"), fullsummary);
4599 : }
4600 : else {
4601 0 : err+= "fullsummary must be a bool";
4602 : }
4603 : }
4604 2518 : if( inrec.isDefined("restoringbeam") )
4605 : {
4606 845 : String errinfo("");
4607 : try {
4608 :
4609 845 : if( inrec.dataType("restoringbeam")==TpString )
4610 : {
4611 16 : err += readVal( inrec, String("restoringbeam"), usebeam);
4612 : // FIXME ! usebeam.length() == 0 is a poorly formed conditional, it
4613 : // probably needs simplification or parenthesis, the compiler is
4614 : // compaining about it
4615 16 : if( (! usebeam.matches("common")) && usebeam.length()!=0 )
4616 : {
4617 4 : Quantity bsize;
4618 4 : err += readVal( inrec, String("restoringbeam"), bsize );
4619 4 : restoringbeam.setMajorMinor( bsize, bsize );
4620 4 : usebeam = String("");
4621 4 : }
4622 16 : errinfo = usebeam;
4623 : }
4624 829 : else if( inrec.dataType("restoringbeam")==TpArrayString )
4625 : {
4626 0 : Vector<String> bpars;
4627 0 : err += readVal( inrec, String("restoringbeam"), bpars );
4628 :
4629 0 : for (uInt i=0;i<bpars.nelements();i++) { errinfo += bpars[i] + " "; }
4630 :
4631 0 : if( bpars.nelements()==1 && bpars[0].length()>0 ) {
4632 0 : if( bpars[0]=="common") { usebeam="common"; }
4633 : else {
4634 0 : Quantity axis; stringToQuantity( bpars[0] , axis);
4635 0 : restoringbeam.setMajorMinor( axis, axis );
4636 0 : }
4637 0 : }else if( bpars.nelements()==2 ) {
4638 0 : Quantity majaxis, minaxis;
4639 0 : stringToQuantity( bpars[0], majaxis ); stringToQuantity( bpars[1], minaxis );
4640 0 : restoringbeam.setMajorMinor( majaxis, minaxis );
4641 0 : }else if( bpars.nelements()==3 ) {
4642 0 : Quantity majaxis, minaxis, pa;
4643 0 : stringToQuantity( bpars[0], majaxis ); stringToQuantity( bpars[1], minaxis ); stringToQuantity( bpars[2], pa );
4644 0 : restoringbeam.setMajorMinor( majaxis, minaxis );
4645 0 : restoringbeam.setPA( pa );
4646 0 : }else {
4647 0 : restoringbeam = GaussianBeam();
4648 0 : usebeam = String("");
4649 : }
4650 0 : }
4651 0 : } catch( AipsError &x) {
4652 0 : err += "Cannot construct a restoringbeam from supplied parameters " + errinfo + ". Please check that majoraxis >= minoraxis and all entries are strings.";
4653 0 : restoringbeam = GaussianBeam();
4654 0 : usebeam = String("");
4655 0 : }
4656 :
4657 845 : }// if isdefined(restoringbeam)
4658 :
4659 2518 : if( inrec.isDefined("interactive") )
4660 : {
4661 2518 : if( inrec.dataType("interactive")==TpBool )
4662 2518 : {err += readVal( inrec, String("interactive"), interactive );}
4663 0 : else if ( inrec.dataType("interactive")==TpInt )
4664 0 : {Int inter=0; err += readVal( inrec, String("interactive"), inter); interactive=(Bool)inter;}
4665 : }
4666 :
4667 : //err += readVal( inrec, String("interactive"), interactive );
4668 :
4669 2518 : err += verify();
4670 :
4671 : }
4672 0 : catch(AipsError &x)
4673 : {
4674 0 : err = err + x.getMesg() + "\n";
4675 0 : }
4676 :
4677 2518 : if( err.length()>0 ) throw(AipsError("Invalid Deconvolver Parameter set : " + err));
4678 :
4679 2518 : }
4680 :
4681 2518 : String SynthesisParamsDeconv::verify() const
4682 : {
4683 2518 : String err;
4684 :
4685 2518 : if( imageName=="" ) {err += "Please supply an image name\n";}
4686 :
4687 : // Allow mask inputs in only one way. User specified OR already on disk. Not both
4688 2518 : if( maskString.length()>0 )
4689 : {
4690 170 : File fp( imageName+".mask" );
4691 170 : if( fp.exists() ) err += "Mask image " + imageName+".mask exists, but a specific input mask of " + maskString + " has also been supplied. Please either reset mask='' to reuse the existing mask, or delete " + imageName + ".mask before restarting";
4692 170 : }
4693 :
4694 2518 : if( pbMask >= 1.0)
4695 0 : {err += "pbmask must be < 1.0 \n"; }
4696 2518 : else if( pbMask < 0.0)
4697 0 : {err += "pbmask must be a positive value \n"; }
4698 :
4699 2518 : if( maskType=="none" )
4700 : {
4701 0 : if( maskString!="" || (maskList.nelements()!=0 && maskList[0]!="") )
4702 : {
4703 0 : cerr<<"maskString="<<maskString<<endl;
4704 0 : cerr<<"maskList.nelements()="<<maskList.nelements()<<" maskList[0]="<<maskList[0]<<endl;
4705 0 : err += "mask is specified but usemask='none'. Please set usemask='user' to use the mask parameter\n";}
4706 : }
4707 2518 : if ( fracOfPeak >= 1.0)
4708 0 : {err += "fracofpeak must be < 1.0 \n"; }
4709 2518 : else if ( fracOfPeak < 0.0)
4710 0 : {err += "fracofpeak must be a positive value \n"; }
4711 :
4712 2518 : return err;
4713 0 : }
4714 :
4715 5040 : void SynthesisParamsDeconv::setDefaults()
4716 : {
4717 5040 : imageName="";
4718 5040 : algorithm="hogbom";
4719 5040 : startModel=Vector<String>(0);
4720 5040 : deconvolverId=0;
4721 5040 : nTaylorTerms=1;
4722 5040 : scales.resize(1); scales[0]=0.0;
4723 5040 : scalebias=0.6;
4724 5040 : maskType="none";
4725 5040 : maskString="";
4726 5040 : maskList.resize(1); maskList[0]="";
4727 5040 : pbMask=0.0;
4728 5040 : autoMaskAlgorithm="thresh";
4729 5040 : maskThreshold="";
4730 5040 : maskResolution="";
4731 5040 : fracOfPeak=0.0;
4732 5040 : nMask=0;
4733 5040 : interactive=false;
4734 5040 : autoAdjust=False;
4735 5040 : fusedThreshold = 0.0;
4736 5040 : specmode="mfs";
4737 5040 : largestscale = -1;
4738 5040 : }
4739 :
4740 1673 : Record SynthesisParamsDeconv::toRecord() const
4741 : {
4742 1673 : Record decpar;
4743 :
4744 1673 : decpar.define("imagename", imageName);
4745 1673 : decpar.define("deconvolver", algorithm);
4746 1673 : decpar.define("startmodel",startModel);
4747 1673 : decpar.define("id",deconvolverId);
4748 1673 : decpar.define("nterms",nTaylorTerms);
4749 1673 : decpar.define("scales",scales);
4750 1673 : decpar.define("scalebias",scalebias);
4751 1673 : decpar.define("usemask",maskType);
4752 1673 : decpar.define("fusedthreshold", fusedThreshold);
4753 1673 : decpar.define("specmode", specmode);
4754 1673 : decpar.define("largestscale", largestscale);
4755 1673 : if( maskList.nelements()==1 && maskList[0]=="")
4756 : {
4757 1121 : decpar.define("mask",maskString);
4758 : }
4759 : else {
4760 552 : decpar.define("mask",maskList);
4761 : }
4762 1673 : decpar.define("pbmask",pbMask);
4763 1673 : if (fracOfPeak > 0.0)
4764 : {
4765 0 : decpar.define("maskthreshold",fracOfPeak);
4766 : }
4767 : else
4768 : {
4769 1673 : decpar.define("maskthreshold",maskThreshold);
4770 : }
4771 1673 : decpar.define("maskresolution",maskResolution);
4772 1673 : decpar.define("nmask",nMask);
4773 1673 : decpar.define("autoadjust",autoAdjust);
4774 1673 : decpar.define("sidelobethreshold",sidelobeThreshold);
4775 1673 : decpar.define("noisethreshold",noiseThreshold);
4776 1673 : decpar.define("lownoisethreshold",lowNoiseThreshold);
4777 1673 : decpar.define("negativethreshold",negativeThreshold);
4778 1673 : decpar.define("smoothfactor",smoothFactor);
4779 1673 : decpar.define("minbeamfrac",minBeamFrac);
4780 1673 : decpar.define("cutthreshold",cutThreshold);
4781 1673 : decpar.define("growiterations",growIterations);
4782 1673 : decpar.define("dogrowprune",doGrowPrune);
4783 1673 : decpar.define("minpercentchange",minPercentChange);
4784 1673 : decpar.define("verbose", verbose);
4785 1673 : decpar.define("fastnoise", fastnoise);
4786 1673 : decpar.define("interactive",interactive);
4787 1673 : decpar.define("nsigma",nsigma);
4788 1673 : decpar.define("noRequireSumwt",noRequireSumwt);
4789 1673 : decpar.define("fullsummary",fullsummary);
4790 :
4791 1673 : return decpar;
4792 0 : }
4793 :
4794 : /////////////////////////////////////////////////////////////////////////////////////////////////////
4795 :
4796 :
4797 : } //# NAMESPACE CASA - END
4798 :
|