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