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