Line data Source code
1 : //# StokesImageUtil.cc: Stokes Image Utilities
2 : //# Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003
3 : //# Associated Universities, Inc. Washington DC, USA.
4 : //#
5 : //# This library is free software; you can redistribute it and/or modify it
6 : //# under the terms of the GNU Library General Public License as published by
7 : //# the Free Software Foundation; either version 2 of the License, or (at your
8 : //# option) any later version.
9 : //#
10 : //# This library 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 Library General Public
13 : //# License for more details.
14 : //#
15 : //# You should have received a copy of the GNU Library General Public License
16 : //# along with this library; if not, write to the Free Software Foundation,
17 : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 : //#
19 : //# Correspondence concerning AIPS++ should be adressed 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 : //#
27 : //# $Id$
28 :
29 : #include <casacore/casa/aips.h>
30 :
31 : #include <casacore/casa/Arrays/Matrix.h>
32 : #include <casacore/casa/Arrays/MatrixMath.h>
33 : #include <casacore/casa/Arrays/ArrayMath.h>
34 : #include <casacore/casa/Arrays/Cube.h>
35 : #include <casacore/casa/BasicMath/Math.h>
36 : #include <casacore/casa/BasicSL/Complex.h>
37 : #include <casacore/scimath/Mathematics/FFTServer.h>
38 : #include <casacore/casa/BasicSL/Constants.h>
39 : #include <casacore/casa/Utilities/Assert.h>
40 : #include <casacore/lattices/Lattices/Lattice.h>
41 : #include <casacore/lattices/LEL/LatticeExpr.h>
42 : #include <casacore/lattices/Lattices/LatticeIterator.h>
43 : #include <casacore/lattices/Lattices/LatticeStepper.h>
44 : #include <casacore/lattices/LatticeMath/LatticeConvolver.h>
45 : #include <casacore/scimath/Fitting/NonLinearFitLM.h>
46 : #include <casacore/scimath/Functionals/Gaussian2D.h>
47 : #include <casacore/scimath/Mathematics/Interpolate2D.h>
48 : #include <casacore/casa/IO/ArrayIO.h>
49 :
50 : #include <casacore/ms/MeasurementSets/MSColumns.h>
51 : #include <casacore/ms/MeasurementSets/MSDopplerUtil.h>
52 :
53 : #include <msvis/MSVis/StokesVector.h>
54 : #include <synthesis/TransformMachines/StokesImageUtil.h>
55 : #include <casacore/images/Images/PagedImage.h>
56 : #include <casacore/images/Images/SubImage.h>
57 : #include <casacore/images/Images/ImageBeamSet.h>
58 : #include <casacore/casa/OS/File.h>
59 :
60 : #include <casacore/casa/Quanta/UnitMap.h>
61 : #include <casacore/casa/Quanta/UnitVal.h>
62 : #include <casacore/measures/Measures/Stokes.h>
63 : #include <casacore/coordinates/Coordinates/CoordinateSystem.h>
64 : #include <casacore/coordinates/Coordinates/DirectionCoordinate.h>
65 : #include <casacore/coordinates/Coordinates/SpectralCoordinate.h>
66 : #include <casacore/coordinates/Coordinates/StokesCoordinate.h>
67 : #include <casacore/coordinates/Coordinates/Projection.h>
68 : #include <casacore/casa/Logging/LogSink.h>
69 : #include <casacore/casa/Logging/LogMessage.h>
70 :
71 : #include <synthesis/TransformMachines2/Utils.h>
72 :
73 : #include <iostream>
74 : #include <ctime>
75 :
76 : using namespace casacore;
77 : namespace casa {
78 :
79 :
80 :
81 : // <summary>
82 : // </summary>
83 :
84 : // <reviewed reviewer="" date="" tests="tMEGI" demos="">
85 :
86 : // <prerequisite>
87 : // </prerequisite>
88 : //
89 : // <etymology>
90 : // </etymology>
91 : //
92 : // <synopsis>
93 : // </synopsis>
94 : //
95 : // <example>
96 : // <srcblock>
97 : // </srcblock>
98 : // </example>
99 : //
100 : // <motivation>
101 : // </motivation>
102 : //
103 : // <todo asof="">
104 : // </todo>
105 :
106 : // In-place convolve. image is 4 dimensional. RA and Dec first.
107 0 : void StokesImageUtil::Convolve(ImageInterface<Float>& image,
108 : ImageInterface<Float>& psf) {
109 :
110 :
111 0 : Double availablemem=Double(HostInfo::memoryFree())*1024.0;
112 : //Do an in memory if x-y complex can fit in remaining memory
113 0 : if(availablemem < Double(image.shape()(0)*image.shape()(1))*6.0*8.0 ){
114 0 : LatticeConvolver<Float> lattCon(psf);
115 0 : lattCon.linear(image);
116 : }
117 : else{
118 :
119 0 : Vector<Int> map;
120 0 : AlwaysAssert(StokesMap(map, image.coordinates()), AipsError);
121 :
122 0 : Vector<Int> psfmap;
123 0 : AlwaysAssert(StokesMap(psfmap, psf.coordinates()), AipsError);
124 :
125 0 : Int nx = image.shape()(map(0));
126 0 : Int ny = image.shape()(map(1));
127 :
128 : // Make FFT machine
129 0 : FFTServer<Float,Complex> fft(IPosition(2, nx, ny));
130 :
131 : // Get the image into a Matrix for Fourier transformation
132 0 : Array<Complex> xfr;
133 0 : Matrix<Complex> cft;
134 :
135 0 : LatticeStepper ls(image.shape(), IPosition(4, nx, ny, 1, 1),
136 0 : IPosition(4, map(0), map(1), map(2), map(3)));
137 0 : LatticeIterator<Float> li(image, ls);
138 :
139 : // Get the PSF into a Matrix for Fourier transformation
140 0 : LatticeStepper psfls(psf.shape(), IPosition(4, nx, ny, 1, 1),
141 0 : IPosition(4, map(0), map(1), map(2), map(3)));
142 0 : RO_LatticeIterator<Float> psfli(psf, psfls);
143 0 : psfli.reset();
144 : //fft.fft(xfr, psfli.matrixCursor());
145 0 : fft.fft0(xfr, psfli.matrixCursor());
146 :
147 : // Loop over all planes
148 0 : for (li.reset();!li.atEnd();li++) {
149 : //fft.fft(cft, li.matrixCursor());
150 0 : fft.fft0(cft,li.matrixCursor());
151 0 : cft *= xfr;
152 : // fft.fft(li.rwMatrixCursor(), cft);
153 0 : fft.fft0(li.rwMatrixCursor(),cft,false);
154 0 : fft.flip(li.rwMatrixCursor(), false, false);
155 : }
156 : }
157 0 : };
158 :
159 0 : void StokesImageUtil::Convolve(ImageInterface<Float>& image,
160 : ImageBeamSet& beams, Bool normalizeVolume){
161 :
162 0 : Int nbeams=beams.shape()(0);
163 :
164 0 : Int freqAx=CoordinateUtil::findSpectralAxis(image.coordinates());
165 0 : Int nchan=image.shape()(freqAx);
166 0 : if((nchan != nbeams) || (nchan==1)){
167 0 : GaussianBeam elbeam=beams(0, 0);
168 0 : Convolve(image, elbeam, normalizeVolume);
169 : }
170 : else{
171 0 : IPosition blc=image.shape();
172 0 : blc=0;
173 0 : IPosition trc=image.shape()-1;
174 0 : for (Int k=0; k < nchan; ++k){
175 0 : blc[freqAx]=k;
176 0 : trc[freqAx]=k;
177 0 : Slicer slc(blc, trc, Slicer::endIsLast);
178 0 : SubImage<Float> subim(image, slc, true);
179 0 : GaussianBeam elbeam=beams(k,0);
180 0 : Convolve(subim, elbeam, normalizeVolume);
181 :
182 : }
183 : }
184 0 : }
185 :
186 0 : void StokesImageUtil::Convolve(ImageInterface<Float>& image,
187 : GaussianBeam& beam,
188 : Bool normalizeVolume)
189 : {
190 0 : Convolve(image, beam.getMajor().get("arcsec").getValue(),
191 0 : beam.getMinor().get("arcsec").getValue(),
192 0 : beam.getPA().get("deg").getValue(),
193 : normalizeVolume);
194 0 : }
195 :
196 0 : void StokesImageUtil::Convolve(ImageInterface<Float>& image, Float bmaj,
197 : Float bmin, Float bpa,
198 : Bool normalizeVolume) {
199 :
200 0 : Vector<Float> beam(3);
201 0 : beam(0)=bmaj*C::arcsec;
202 0 : beam(1)=bmin*C::arcsec;
203 0 : beam(2)=(bpa+90.0)*C::degree;
204 : PagedImage<Float>
205 0 : cleanpsf(IPosition(4, image.shape()(0), image.shape()(1), 1, 1),
206 : image.coordinates(),
207 0 : File::newUniqueName("./","imagesolver::cleanpsf").originalName());
208 0 : cleanpsf.table().markForDelete();
209 0 : MakeGaussianPSF(cleanpsf, beam, normalizeVolume);
210 0 : Convolve(image, cleanpsf);
211 0 : }
212 :
213 0 : void StokesImageUtil::MakeGaussianPSF(ImageInterface<Float>& psf,
214 : Quantity& bmaj, Quantity& bmin,
215 : Quantity& bpa,
216 : Bool normalizeVolume)
217 : {
218 0 : Vector<Float> beam(3);
219 0 : beam(0)=bmaj.get("arcsec").getValue();
220 0 : beam(1)=bmin.get("arcsec").getValue();
221 0 : beam(2)=bpa.get("deg").getValue();
222 0 : MakeGaussianPSF(psf, beam, normalizeVolume);
223 0 : }
224 :
225 : // Make an image into a Gaussian PSF
226 0 : void StokesImageUtil::MakeGaussianPSF(ImageInterface<Float>& psf, Vector<Float>& beam,
227 : Bool normalizeVolume) {
228 :
229 0 : Int nx=psf.shape()(0);
230 0 : Int ny=psf.shape()(1);
231 0 : Matrix<Float> ipsf(nx, ny);
232 :
233 0 : Double cospa=cos(beam(2));
234 0 : Double sinpa=sin(beam(2));
235 0 : Vector<Double> rp=psf.coordinates().referencePixel();
236 0 : Vector<Double> d=psf.coordinates().increment();
237 0 : Double refi=rp(0);
238 0 : Double refj=rp(1);
239 0 : AlwaysAssert(beam(0)>0.0,AipsError);
240 0 : AlwaysAssert(beam(1)>0.0,AipsError);
241 : Double sbmaj, sbmin;
242 :
243 : // ---old
244 : // Assumes that the cell sizes are the same in both directions!
245 : //sbmaj=4.0*log(2.0)*square(d(0)/beam(0));
246 : //sbmin=4.0*log(2.0)*square(d(0)/beam(1));
247 : // ---old
248 :
249 : // Evaluate the Gaussian beam using real-world coordinates, to handle rectangular pixels (cas-7171)
250 0 : sbmaj=4.0*log(2.0)*square(1.0/beam(0));
251 0 : sbmin=4.0*log(2.0)*square(1.0/beam(1));
252 :
253 0 : Vector<Double>fd(fabs(d));
254 :
255 0 : Float volume=0.0;
256 0 : for (Int j=0;j<ny;j++) {
257 0 : for (Int i=0;i<nx;i++) {
258 : // ---old
259 : // Double x = cospa * (Double(i)-refi) + sinpa * (Double(j)-refj);
260 : // Double y = - sinpa * (Double(i)-refi) + cospa * (Double(j)-refj);
261 : // ---old
262 0 : Double x = cospa * (Double(i)-refi)*fd(0) + sinpa * (Double(j)-refj)*fd(1);
263 0 : Double y = - sinpa * (Double(i)-refi)*fd(0) + cospa * (Double(j)-refj)*fd(1);
264 0 : Double radius = sbmaj*square(x) + sbmin*square(y);
265 0 : if (radius<20.) {
266 0 : ipsf(i,j) = exp(-radius);
267 0 : volume+=ipsf(i,j);
268 : }
269 : else {
270 0 : ipsf(i,j)=0.;
271 : }
272 : }
273 : }
274 0 : if(normalizeVolume) ipsf/=volume;
275 0 : psf.putSlice(ipsf, IPosition(psf.ndim(),0), IPosition(psf.ndim(),1));
276 :
277 0 : }
278 :
279 0 : Float StokesImageUtil::normalizePSF(casacore::ImageInterface<casacore::Float>& psf){
280 0 : AlwaysAssert(psf.ndim()==4,AipsError);
281 :
282 0 : Float retval=-1e10;
283 0 : Vector<Int> map;
284 0 : AlwaysAssert(StokesMap(map, psf.coordinates()), AipsError);
285 0 : Int nx = psf.shape()(map(0));
286 0 : Int ny = psf.shape()(map(1));
287 0 : if(nx < 32 || ny < 32)
288 0 : throw(AipsError("Will not normalize images less than 32 pixels"));
289 0 : Int npol = psf.shape()(map(2));
290 0 : Int nchan = psf.shape()(map(3));
291 0 : IPosition blc(4);
292 0 : IPosition trc(4);
293 0 : IPosition blc8(4,0,0,0,0);
294 0 : IPosition trc8(4,0,0,0,0);
295 0 : blc(map(0))=0; blc(map(1))=0;
296 0 : trc(map(0))=nx-1; trc(map(1))=ny-1;
297 0 : blc8(map(0))=nx/2-nx/16; blc8(map(1))=ny/2-ny/16;
298 0 : trc8(map(0))=nx/2+nx/16; trc8(map(1))=ny/2+ny/16;
299 0 : Slicer inner8(blc8, trc8, Slicer::endIsLast);
300 0 : for (Int k=0; k < nchan ; ++k){
301 0 : blc(map(3))=k;
302 0 : trc(map(3))=k;
303 0 : for (Int j=0; j < npol; ++j){
304 0 : blc(map(2))=j;
305 0 : trc(map(2))=j;
306 0 : Slicer sl(blc, trc, Slicer::endIsLast);
307 0 : SubImage<Float> psfSub(psf, sl, True);
308 0 : Float maxCenter=max(psfSub.getSlice(inner8));
309 0 : if(maxCenter > retval)
310 0 : retval=maxCenter;
311 0 : if(maxCenter !=0){
312 0 : psfSub.copyData( (LatticeExpr<Float>)(psfSub/maxCenter));
313 : }
314 : else{
315 0 : psfSub.set(0.0);
316 : }
317 : }
318 : }
319 0 : return retval;
320 : }
321 :
322 :
323 : // Zero specified elements of a Stokes image
324 0 : void StokesImageUtil::Zero(ImageInterface<Float>& image, Vector<Bool>& mask) {
325 :
326 0 : AlwaysAssert(image.ndim()==4,AipsError);
327 0 : AlwaysAssert(mask.shape()(0)==4,AipsError);
328 :
329 0 : Vector<Int> map;
330 0 : AlwaysAssert(StokesMap(map, image.coordinates()), AipsError);
331 :
332 0 : Int nx = image.shape()(map(0));
333 0 : Int ny = image.shape()(map(1));
334 0 : Int npol = image.shape()(map(2));
335 0 : Int nchan = image.shape()(map(3));
336 :
337 0 : LatticeStepper ls(image.shape(), IPosition(4, nx, 1, 1, 1),
338 0 : IPosition(4, map(0), map(1), map(2), map(3)));
339 0 : LatticeIterator<Float> li(image, ls);
340 :
341 : // Loop over all planes
342 0 : li.reset();
343 0 : for (Int chan=0;chan<nchan;chan++) {
344 0 : for(Int pol=0;pol<npol;pol++) {
345 0 : for(Int iy=0;iy<ny;iy++,li++) {
346 0 : if(mask(pol)) {
347 0 : li.woVectorCursor()=0.0;
348 : }
349 : }
350 : }
351 : }
352 :
353 0 : }
354 :
355 0 : void StokesImageUtil::MaskFrom(ImageInterface<Float>& mask,
356 : ImageInterface<Float>& image,
357 : const Quantity& threshold)
358 : {
359 0 : MaskFrom(mask, image, threshold.get("Jy").getValue());
360 0 : }
361 :
362 0 : void StokesImageUtil::MaskFrom(ImageInterface<Float>& mask,
363 : ImageInterface<Float>& image,
364 : const Double thres)
365 : {
366 0 : AlwaysAssert(image.ndim()==4,AipsError);
367 0 : AlwaysAssert(mask.shape()==image.shape(),AipsError);
368 :
369 0 : Vector<Int> map;
370 0 : AlwaysAssert(StokesMap(map, image.coordinates()), AipsError);
371 :
372 0 : Int nx = image.shape()(map(0));
373 0 : Int npol = image.shape()(map(2));
374 :
375 0 : LatticeStepper ls(image.shape(), IPosition(4, nx, 1, npol, 1),
376 0 : IPosition(4, map(0), map(1), map(2), map(3)));
377 0 : RO_LatticeIterator<Float> li(image, ls);
378 0 : LatticeIterator<Float> mli(mask, ls);
379 :
380 : // Loop over all planes
381 0 : for (li.reset(),mli.reset();!li.atEnd()&&!mli.atEnd();li++,mli++) {
382 0 : if(npol>1) {
383 0 : mli.rwMatrixCursor()=0.0;
384 0 : for (Int ix=0;ix<nx;ix++) {
385 0 : if(li.matrixCursor()(ix,0)>thres) {
386 0 : for (Int pol=0;pol<npol;pol++) mli.rwMatrixCursor()(ix,pol)=1.0;
387 : }
388 : }
389 : }
390 : else {
391 0 : mli.rwVectorCursor()=0.0;
392 0 : for (Int ix=0;ix<nx;ix++) {
393 0 : if(li.vectorCursor()(ix)>thres) {
394 0 : mli.rwVectorCursor()(ix)=1.0;
395 : }
396 : }
397 : }
398 : }
399 0 : }
400 :
401 0 : void StokesImageUtil::MaskOnStokesI(ImageInterface<Float>& image,
402 : const Quantity& threshold)
403 : {
404 :
405 0 : Double thres=threshold.get("Jy").getValue();
406 :
407 0 : AlwaysAssert(image.ndim()==4,AipsError);
408 :
409 0 : Vector<Int> map;
410 0 : AlwaysAssert(StokesMap(map, image.coordinates()), AipsError);
411 :
412 0 : Int nx = image.shape()(map(0));
413 0 : Int npol = image.shape()(map(2));
414 :
415 0 : LatticeStepper ls(image.shape(), IPosition(4, nx, 1, npol, 1),
416 0 : IPosition(4, map(0), map(1), map(2), map(3)));
417 0 : LatticeIterator<Float> li(image, ls);
418 :
419 : // Loop over all planes
420 0 : for (li.reset();!li.atEnd();li++) {
421 0 : for (Int ix=0;ix<nx;ix++) {
422 0 : if(npol>1) {
423 0 : if(li.matrixCursor()(ix,0)<thres) {
424 0 : for (Int pol=0;pol<npol;pol++) li.rwMatrixCursor()(ix,pol)=0.0;
425 : }
426 : }
427 : else {
428 0 : if(li.vectorCursor()(ix)<thres) {
429 0 : li.rwVectorCursor()(ix)=0.0;
430 : }
431 : }
432 : }
433 : }
434 :
435 0 : }
436 :
437 : // Constrain (a) Stokes I to be > 0 and (b) I > abs(V) and
438 : // (c) fractional pol<1.0
439 0 : void StokesImageUtil::Constrain(ImageInterface<Float>& image) {
440 :
441 0 : AlwaysAssert(image.ndim()==4,AipsError);
442 :
443 0 : Vector<Int> map;
444 0 : AlwaysAssert(StokesMap(map, image.coordinates()), AipsError);
445 :
446 0 : Int nx = image.shape()(map(0));
447 0 : Int npol = image.shape()(map(2));
448 :
449 0 : LatticeStepper ls(image.shape(), IPosition(4, nx, 1, npol, 1),
450 0 : IPosition(4, map(0), map(2), map(1), map(3)));
451 0 : LatticeIterator<Float> li(image, ls);
452 :
453 : // Loop over all planes
454 0 : for (li.reset();!li.atEnd();li++) {
455 :
456 : // Make a copy of the cursor
457 0 : Matrix<Float>& limage=li.rwMatrixCursor();
458 :
459 0 : for (Int ix=0;ix<nx;ix++) {
460 : // I >=0
461 0 : Bool zero=false;
462 0 : if(limage(ix,0)<0.0) {
463 0 : zero=true;
464 : }
465 : // I >= abs(V)
466 0 : else if (npol==2) {
467 0 : if(limage(ix,0)<abs(limage(ix,1))) zero=true;
468 : }
469 : // fractional pol < 1.0
470 0 : else if (npol==4) {
471 0 : StokesVector sv(limage(ix,0),limage(ix,1),
472 0 : limage(ix,2),limage(ix,3));
473 0 : if(sv.minEigenValue()<0.0) zero=true;
474 : }
475 0 : if(zero) for (Int pol=0;pol<npol;pol++) limage(ix,pol)=0.0;
476 : }
477 : }
478 0 : }
479 :
480 : //See CAS-13022 for FitGaussianPSF algorithm details
481 0 : Bool StokesImageUtil::FitGaussianPSF(ImageInterface<Float>& psf, ImageBeamSet& elbeam, Float psfcutoff){
482 :
483 0 : Bool retval=true;
484 0 : Int freqAx=CoordinateUtil::findSpectralAxis(psf.coordinates());
485 0 : Vector<Stokes::StokesTypes> whichPols;
486 0 : Int polAx=CoordinateUtil::findStokesAxis(whichPols, psf.coordinates());
487 0 : Int nchan=psf.shape()(freqAx);
488 0 : IPosition blc=psf.shape();
489 0 : blc=0;
490 0 : IPosition trc=psf.shape()-1;
491 0 : trc[polAx]=0;
492 0 : elbeam=ImageBeamSet(nchan, 1);
493 0 : IPosition ipos(2,0,0);
494 0 : Matrix<GaussianBeam> tempBeam(nchan,1);
495 0 : Vector<Bool> fitted(nchan, false);
496 :
497 0 : for (Int k=0; k < nchan;++k){
498 0 : blc[freqAx]=k;
499 0 : trc[freqAx]=k;
500 0 : Slicer slc(blc, trc, Slicer::endIsLast);
501 0 : SubImage<Float> subpsf(psf, slc, false);
502 : try{
503 0 : fitted(k)=FitGaussianPSF(subpsf, tempBeam(k,0), psfcutoff);
504 : }
505 0 : catch (AipsError x_error){
506 0 : Int ik=k;
507 0 : fitted(k)=false;
508 0 : while ((ik > 0) && !fitted(k)){
509 0 : if(fitted(ik-1)){
510 0 : fitted(k)=true;
511 0 : tempBeam(k,0)=tempBeam(ik-1, 0);
512 : }
513 0 : --ik;
514 : }
515 : }
516 0 : ipos(0)=k;
517 : }
518 0 : Float maxMaj=0.0;
519 0 : Float minMaj=C::flt_max;
520 0 : Int posMax=0;
521 0 : DirectionCoordinate directionCoord=psf.coordinates().directionCoordinate(psf.coordinates().findCoordinate(Coordinate::DIRECTION));
522 0 : String dirunit=directionCoord.worldAxisUnits()(0);
523 0 : for(Int k=0; k < nchan; ++k){
524 0 : if(fitted(k) && (maxMaj < tempBeam(k,0).getMajor(dirunit))){
525 0 : maxMaj=tempBeam(k,0).getMajor(dirunit);
526 0 : posMax=k;
527 : }
528 0 : if(fitted(k) && (minMaj > tempBeam(k,0).getMajor(dirunit))){
529 0 : minMaj=tempBeam(k,0).getMajor(dirunit);
530 0 : posMax=k;
531 : }
532 : }
533 : //If the beams are within 0.5 pixel the same resolution then
534 : //who cares to have a beam per plane
535 0 : if(abs(minMaj-maxMaj) < 0.5*abs(directionCoord.increment()(0))){
536 0 : GaussianBeam theBeam=tempBeam(posMax,0);
537 0 : tempBeam.resize(1,1);
538 0 : tempBeam(0,0)=theBeam;
539 0 : fitted.resize(1);
540 0 : fitted=true;
541 : }
542 0 : if(!anyTrue(fitted)){
543 0 : retval=false;
544 0 : throw(AipsError("No valid fits were found to PSF"));
545 : }
546 0 : if(!allTrue(fitted)){
547 0 : for (Int k=0; k < nchan;++k){
548 0 : int ik=k;
549 0 : while((ik < (nchan-1)) && !fitted(k)){
550 0 : if(fitted(ik+1)){
551 0 : fitted(k)=true;
552 0 : tempBeam(k,0)=tempBeam(ik+1, 0);
553 : }
554 0 : ++ik;
555 : }
556 : }
557 : }
558 0 : elbeam=ImageBeamSet(tempBeam.shape());
559 0 : elbeam.setBeams(tempBeam);
560 :
561 0 : return retval;
562 : }
563 :
564 0 : Bool StokesImageUtil::FitGaussianPSF(ImageInterface<Float>& psf,
565 : GaussianBeam& beam, Float psfcutoff)
566 : {
567 0 : Vector<Float> vbeam(3, 0.0);
568 0 : Bool status=true;
569 0 : if(!FitGaussianPSF(psf, vbeam, psfcutoff)) status=false;
570 0 : beam = GaussianBeam(
571 0 : Quantity(abs(vbeam[0]),"arcsec"),
572 0 : Quantity(abs(vbeam[1]),"arcsec"),
573 0 : Quantity(vbeam[2],"deg")
574 0 : );
575 0 : return status;
576 :
577 : }
578 :
579 :
580 0 : void StokesImageUtil::FindNpoints(Int& npoints, IPosition& blc, IPosition& trc, Int nrow, Float amin, Int px, Int py, Vector<Double>& deltas, Matrix<Double>& x , Vector<Double>& y, Vector<Double>& sigma, Matrix<Float>& lpsf){
581 :
582 0 : Int maxnpoints=(2*nrow+1)*(2*nrow+1);
583 0 : Matrix<Double> ix(maxnpoints,2);
584 0 : Vector<Double> iy(maxnpoints), isigma(maxnpoints);
585 0 : ix=0.0; iy=0.0; isigma=0.0;
586 0 : npoints = 0;
587 :
588 : //IPosition blc(2), trc(2);
589 : //blc = 0; trc = 0;
590 :
591 0 : blc(0) = lpsf.shape()(0)-1;
592 0 : blc(1) = lpsf.shape()(1)-1;
593 0 : trc(0) = 0;
594 0 : trc(1) = 0;
595 :
596 0 : IPosition psf_shape = lpsf.shape();
597 :
598 : //we sample the central part of a, 2*nrow+1 by 2*nrow+1
599 :
600 0 : Int iflip = 1;
601 0 : Int jflip = 1;
602 : // loop through rows. Include both above and below in case
603 : // we are fitting an image feature
604 :
605 0 : for(Int jlo = 0;jlo<2;jlo++) {
606 0 : jflip*=-1;
607 : // loop from 0 to nrow then from 1 to nrow
608 0 : for(Int j = jlo;j<=nrow;j++) {
609 : // the current row under consideration
610 0 : Int jrow = py + j*jflip;
611 : // loop down row doing alternate halves. work our way
612 : // out from the center until we cross threshold
613 : // don't include any sidelobes!
614 0 : for(Int ilo=0;ilo<2;ilo++) {
615 0 : iflip*=-1;
616 : // start at center row this may or may not be in the lobe,
617 : // if it's narrow and the pa is near 45 degrees
618 :
619 :
620 0 : if((jrow > (psf_shape(1)-1)) || (jrow < 0 ) ) break;
621 : //cout << "11.** " << maxnpoints << ",*,"<< npoints << ",*," << px << ",*," << jrow << endl;
622 0 : Bool inlobe = lpsf(px,jrow)>amin;
623 :
624 : //cout << "12.** " << maxnpoints << ",*,"<< npoints << ",*," << px << ",*," << jrow << endl;
625 0 : for(Int i = ilo;i<=nrow;i++) {
626 0 : if(npoints < maxnpoints){
627 0 : Int irow = px + i*iflip;
628 : // did we step out of the lobe?
629 :
630 0 : if((irow > (psf_shape(0)-1)) || (irow < 0 ) ) break;
631 : //cout << "irow , jrow " << irow << ",*," << jrow << ",*," << lpsf.shape() << ",*," << px << ",*," << py << endl;
632 0 : if (inlobe&&(lpsf(irow,jrow)<amin)) break;
633 0 : if (lpsf(irow,jrow)>amin) {
634 : //cout << "$%$irow , jrow " << lpsf.shape() << ",*,"<< irow << "," << jrow << ",*, "<< irow - px << ",*," << jrow - py << ",*, " << lpsf(irow,jrow) << ",*, " << inlobe << ",*, " << npoints << endl;
635 0 : inlobe = true;
636 : // the sign on the ra can cause problems. we just fit
637 : // for what the beam "looks" like here, and worry about
638 : // it later.
639 0 : ix(npoints,0) = (irow-px)*abs(deltas(0));
640 0 : ix(npoints,1) = (jrow-py)*abs(deltas(1));
641 0 : iy(npoints) = lpsf(irow,jrow);
642 : //cout << "1.**" << endl;
643 :
644 0 : if(blc(0) > irow) blc(0) = irow;
645 0 : if(blc(1) > jrow) blc(1) = jrow;
646 :
647 0 : if(trc(0) < irow) trc(0) = irow;
648 0 : if(trc(1) < jrow) trc(1) = jrow;
649 : //cout << "2.**" << endl;
650 :
651 0 : isigma(npoints) = 1.0;
652 0 : ++npoints;
653 : // cout << "3.** " << maxnpoints << ",*,"<< npoints << endl;
654 0 : if(npoints > (maxnpoints-1)) {
655 0 : inlobe=false;
656 : //cout << "Over max points .** " << maxnpoints << ",*,"<< npoints << endl;
657 : //break;
658 0 : goto endSearch;
659 : }
660 : // cout << "5.** " << maxnpoints << ",*,"<< npoints << endl;
661 : }
662 : }
663 : }
664 : }
665 : }
666 : }
667 :
668 0 : endSearch:
669 :
670 : //cout << "2. blc, trc " << blc << ",*," << trc << endl;
671 : //Vector<Double> y(npoints), sigma(npoints);
672 : //Matrix<Double> x(npoints,2);
673 : //cout << "hallo " << endl;
674 :
675 0 : y.resize(npoints);
676 0 : x.resize(npoints,2);
677 0 : sigma.resize(npoints);
678 :
679 : //cout << "2. findNPoints " << npoints << " " << amin << endl;
680 :
681 0 : for (Int ip=0;ip<npoints;ip++) {
682 0 : x(ip,0)=ix(ip,0); x(ip,1)=ix(ip,1);
683 0 : y(ip)=iy(ip);
684 0 : sigma(ip)=isigma(ip);
685 0 : if(!(isigma(ip)>0.0)) break;
686 : }
687 :
688 : //Ensure that it is square
689 0 : if(blc(0) > blc(1)){
690 0 : blc(0) = blc(1);
691 : }else{
692 0 : blc(1) = blc(0);
693 : }
694 :
695 0 : if(trc(0) > trc(1)){
696 0 : trc(1) = trc(0);
697 : }else{
698 0 : trc(0) = trc(1);
699 : }
700 :
701 :
702 0 : }
703 :
704 0 : void StokesImageUtil::ResamplePSF(Matrix<Float>& psf, Int& oversampling, Matrix<Float>& resampledPsf, String& InterpMethod)
705 : {
706 0 : Int nx = psf.shape()(0);
707 0 : Int ny = psf.shape()(1);
708 0 : Int nxRe = nx*oversampling - oversampling + 1;
709 0 : Int nyRe = ny*oversampling - oversampling + 1;
710 :
711 0 : Vector<Double> pos(2);
712 0 : resampledPsf.resize(nxRe,nyRe);
713 :
714 : Interpolate2D::Method method;
715 0 : if(InterpMethod == "NEAREST") method = Interpolate2D::NEAREST;
716 0 : if(InterpMethod == "LINEAR") method = Interpolate2D::LINEAR;
717 0 : if(InterpMethod == "CUBIC") method = Interpolate2D::CUBIC;
718 0 : if(InterpMethod == "LANCZOS") method = Interpolate2D::LANCZOS;
719 :
720 0 : Interpolate2D resampleInterp(method);
721 : //Interpolate2D resampleInterp(Interpolate2D::CUBIC);
722 :
723 : Bool ok;
724 : Float result;
725 :
726 0 : for (Int i=0; i < nxRe ; ++i){
727 0 : for (Int j=0; j < nyRe ; ++j){
728 0 : pos(0) = (Float) i/(Float) oversampling;
729 0 : pos(1) = (Float) j/(Float) oversampling;
730 :
731 0 : ok = resampleInterp.interp(result, pos, psf);
732 : //cout << "pos is" << pos << " result " << result << " psf " << psf(i,j)<< endl;
733 0 : resampledPsf(i,j) = result;
734 : }
735 : }
736 :
737 :
738 0 : }
739 :
740 :
741 0 : Bool StokesImageUtil::FitGaussianPSF(ImageInterface<Float>& psf, Vector<Float>& beam, Float psfcutoff) {
742 :
743 0 : LogIO os(LogOrigin("StokesImageUtil", "FitGaussianPSF()",WHERE));
744 0 : os << LogIO::DEBUG1 << "Psfcutoff is " << psfcutoff << LogIO::POST;
745 :
746 0 : Float npix = 20;
747 0 : Int expand_pixel = 5;
748 0 : Int target_npoints = 3001;
749 0 : String InterpMethod = "CUBIC";
750 :
751 : //##########################################################
752 :
753 0 : Vector<Double> deltas;
754 0 : deltas=psf.coordinates().increment();
755 :
756 0 : Vector<Int> map;
757 0 : AlwaysAssert(StokesMap(map, psf.coordinates()), AipsError);
758 :
759 0 : Int nx = psf.shape()(map(0));
760 0 : Int ny = psf.shape()(map(1));
761 : //// Int nchan = psf.shape()(map(3)); // apparently not used and no side effects
762 0 : Int px=0;
763 0 : Int py=0;
764 0 : Float bamp=0;
765 0 : Matrix<Float> lpsf;
766 0 : locatePeakPSF(psf, px, py, bamp, lpsf);
767 :
768 : //check if peak is ZERO
769 0 : if( bamp < 1e-07 ) {
770 0 : throw(AipsError("Psf peak is zero"));
771 : }
772 :
773 : //check if peak is outside inner quarter
774 0 : if(px < nx/4.0 || px > 3.0*nx/4.0 || py < ny/4.0 || py > 3.0*ny/4.0) {
775 0 : throw(AipsError("Peak of psf is outside the inner quarter of defined image"));
776 : }
777 :
778 :
779 0 : if((bamp > 1.1) || (bamp < 0.9)) // No warning if 10% error in PSF peak
780 0 : os << LogIO::WARN << "Peak of PSF is " << bamp << LogIO::POST;
781 :
782 :
783 0 : static const Float fdiam = 2.5*abs(deltas(0))/C::arcsec;
784 : try{
785 :
786 :
787 0 : if(bamp==0.0) {
788 0 : beam[0] = fdiam;
789 0 : beam[1] = fdiam;
790 0 : beam[2] = 0.0;
791 0 : os << LogIO::WARN << "Could not find peak " << LogIO::POST;
792 0 : return false;
793 : }
794 :
795 :
796 :
797 0 : lpsf/=bamp; //Normalize
798 :
799 : // The selection code attempts to avoid including any sidelobes, even
800 : // if they exceed the threshold, by starting from the center column and
801 : // working out, exiting the loop when it crosses the threshold. It
802 : // assumes that the first time it finds a "good" point starting from
803 : // the center and working out that it's in the main lobe. Narrow,
804 : // sharply ringing beams inclined at 45 degrees will confuse it, but
805 : // that's even more pathological than most VLBI beams.
806 :
807 0 : Float amin=psfcutoff;
808 0 : Int nrow=npix;
809 :
810 : //we sample the central part of a, 2*nrow+1 by 2*nrow+1
811 0 : Bool converg=false;
812 0 : Vector<Double> solution;
813 0 : Int kounter=0;
814 :
815 0 : while(amin > 0.009 && !converg && (kounter < 50)){
816 0 : kounter+=1;
817 0 : Int npoints=0;
818 0 : Vector<Double> y, sigma;
819 0 : Matrix<Double> x;
820 0 : IPosition blc(2), trc(2);
821 :
822 0 : FindNpoints(npoints, blc, trc, nrow, amin, px, py, deltas, x , y, sigma, lpsf);
823 0 : os << LogIO::DEBUG1 << "First FindNpoints is " << npoints << LogIO::POST;
824 :
825 0 : blc = blc-expand_pixel;
826 0 : trc = trc+expand_pixel;
827 :
828 0 : if(blc(0) < 0) blc(0)=0;
829 0 : if(blc(1) < 0) blc(1)=0;
830 0 : if(trc(0) >= lpsf.shape()(0)) trc(0)=lpsf.shape()(0)-1;
831 0 : if(trc(1) >= lpsf.shape()(1)) trc(1)=lpsf.shape()(1)-1;
832 :
833 0 : Matrix<Float> lpsfWindowed = lpsf(blc,trc);
834 0 : os << LogIO::DEBUG1 << "The windowed Psf shape is " << lpsfWindowed.shape() << LogIO::POST;
835 0 : Matrix<Float> resampledPsf;
836 :
837 0 : Int oversampling = (Int) sqrt(target_npoints/(lpsfWindowed.shape()(0)*lpsfWindowed.shape()(1)));
838 0 : if(oversampling == 0){
839 0 : oversampling = 1;
840 : }
841 0 : os << LogIO::DEBUG1 << "The oversampling is " << oversampling << LogIO::POST;
842 :
843 0 : ResamplePSF(lpsfWindowed, oversampling, resampledPsf,InterpMethod);
844 0 : os << LogIO::DEBUG1 << "The resampled windowed Psf shape is " << lpsfWindowed.shape() << LogIO::POST;
845 :
846 : Float minVal, maxVal;
847 0 : IPosition minPos(2);
848 0 : IPosition maxPos(2);
849 0 : minMax(minVal, maxVal, minPos, maxPos, resampledPsf);
850 0 : resampledPsf = resampledPsf/maxVal;
851 :
852 0 : Vector<Double> resampledDeltas = deltas/ (Double) oversampling;
853 :
854 : Int minLen;
855 0 : if((trc(0) - blc(0)) > (trc(1) - blc(1)) ){
856 0 : minLen = trc(1) - blc(1) + 1;
857 : }else{
858 0 : minLen = trc(0) - blc(0) + 1;
859 : }
860 :
861 0 : Int nrowRe = (Int) (oversampling*minLen - 1)/2;
862 0 : FindNpoints(npoints, blc, trc, nrowRe, amin, maxPos(0), maxPos(1), resampledDeltas, x , y, sigma, resampledPsf);
863 0 : os << LogIO::DEBUG1 << "Second FindNpoints is " << npoints << LogIO::POST;
864 :
865 0 : Gaussian2D<AutoDiff<Double> > gauss2d;
866 0 : gauss2d[0] = 1.0; //Height of Gaussian
867 0 : gauss2d[1] = 0.0; //The center of the Gaussian in the x direction
868 0 : gauss2d[2] = 0.0; //The center of the Gaussian in the y direction.
869 : //gauss2d[3] = 2.5*abs(resampledDeltas(0)); //The width (FWHM) of the Gaussian on one axis.
870 0 : gauss2d[3] = 2.5*abs(deltas(0));
871 0 : gauss2d[4] = 0.5; //A modified axial ratio.
872 :
873 : // Fix height and center
874 0 : gauss2d.mask(0) = false;
875 0 : gauss2d.mask(1) = false;
876 0 : gauss2d.mask(2) = false;
877 :
878 : // CAS-13515: Fitting sometimes fails with "NonLinearFitLM: error in loop solution". This occurs in casacore/scimath/Fitting/NonLinearFitLM.tcc LSQFit::invertRect() due to a matrix that can not be inverted.
879 : // This problem is solved by retrying fit with a different position angle.
880 0 : Bool loopSolutionFound=false;
881 0 : Int retryCounter = 0;
882 0 : Double posAng = 1.0; //Initial position angle.
883 0 : Int nRetries = 10;
884 0 : while(!loopSolutionFound && retryCounter < nRetries){
885 : //Create casacore fitter and fit Gaussian to subset of PSF interpolated values.
886 0 : gauss2d[5] = posAng; //The position angle.
887 0 : NonLinearFitLM<Double> fitter;
888 : // Set maximum number of iterations to 1000
889 0 : fitter.setMaxIter(1000);
890 :
891 : // Set converge criteria. Default is 0.001
892 0 : fitter.setCriteria(0.0001);
893 :
894 : // Set the function and initial values
895 0 : fitter.setFunction(gauss2d);
896 :
897 : try{
898 : // The current parameter values are used as the initial guess.
899 0 : solution = fitter.fit(x, y, sigma);
900 0 : loopSolutionFound = true;
901 0 : }catch(AipsError x_error){
902 0 : loopSolutionFound = false;
903 0 : retryCounter++;
904 0 : posAng = 1.0 + retryCounter*M_PI/nRetries;
905 0 : os << LogIO::NORMAL3 << "Fit failed, another atempt will be made with position angle " << posAng << " rad." << LogIO::POST;
906 : }
907 0 : converg=fitter.converged();
908 : }
909 :
910 0 : if(!loopSolutionFound)
911 : {
912 0 : throw(AipsError(String("Error in StokesImageUtil::FitGaussianPSF: error in loop solution.")));
913 : }
914 :
915 0 : if (!converg) {
916 0 : beam(0)=2.5*abs(deltas(0))/C::arcsec;
917 0 : beam(1)=2.5*abs(deltas(0))/C::arcsec;
918 0 : beam(2)=0.0;
919 :
920 : //fit did not coverge...reduce the minimum i.e expand the field a bit
921 0 : amin/=1.5;
922 :
923 0 : os << LogIO::WARN << "The fit did not coverge; another atempt will be made with psfcutoff " << amin << LogIO::POST;
924 : }
925 :
926 : }
927 0 : if (converg) {
928 0 : if (abs(solution(4))>1.0) {
929 0 : beam(0)=abs(solution(3)*solution(4))/C::arcsec;
930 0 : beam(1)=abs(solution(3))/C::arcsec;
931 0 : beam(2)=solution(5)/C::degree-90.0;
932 : } else {
933 0 : beam(0)=abs(solution(3))/C::arcsec;
934 0 : beam(1)=abs(solution(3)*solution(4))/C::arcsec;
935 0 : beam(2)=solution(5)/C::degree;
936 : }
937 :
938 0 : beam(2)=fmod(beam(2), Float(360.0));
939 : //while (abs(beam(2)/180.0)> 1) {
940 : // if (beam(2) > 180.0) beam(2)-=360.0;
941 : // else beam(2)+=360.0;
942 : //}
943 : //CAS-8627: adjust pa to the range -90d, +90d
944 0 : while (abs(beam(2)/90.0)> 1) {
945 0 : if (beam(2) > 270.0) beam(2)-=360.0;
946 0 : else if (beam(2) > 90.0) beam(2) -=180.0;
947 0 : else if (beam(2) < -270.0) beam(2) +=360.0;
948 0 : else beam(2)+=180.0;
949 : }
950 :
951 0 : return true;
952 : }
953 : else os << LogIO::WARN << "The fit did not coverge; check your PSF" <<
954 0 : LogIO::POST;
955 0 : return false;
956 :
957 0 : } catch (AipsError x_error) {
958 0 : beam[0] = fdiam;
959 0 : beam[1] = fdiam;
960 0 : beam[2] = 0.0;
961 : os << LogIO::SEVERE << "Caught Exception: "<< x_error.getMesg() <<
962 0 : LogIO::POST;
963 0 : return false;
964 : }
965 :
966 : }
967 :
968 0 : void StokesImageUtil::locatePeakPSF(ImageInterface<Float>& in, Int& xpos, Int& ypos, Float& amp, Matrix<Float>& lpsf){
969 0 : Vector<Int> map;
970 0 : AlwaysAssert(StokesMap(map, in.coordinates()), AipsError);
971 :
972 0 : Int nx = in.shape()(map(0));
973 0 : Int ny = in.shape()(map(1));
974 0 : Int nchan = in.shape()(map(3));
975 0 : xpos=0;
976 0 : ypos=0;
977 : Float psfmax;
978 :
979 0 : amp=0;
980 :
981 :
982 0 : IPosition oneplane(in.ndim(), nx, ny, 1, 1);
983 0 : LatticeStepper psfls(in.shape(), oneplane,
984 0 : IPosition(4,map(0),map(1),map(3),map(2)));
985 0 : RO_LatticeIterator<Float> psfli(in,psfls);
986 0 : while (nchan >= 1 && amp < 0.9){
987 0 : lpsf=psfli.matrixCursor();
988 :
989 0 : IPosition psfposmax(lpsf.ndim());
990 0 : IPosition psfposmin(lpsf.ndim());
991 : Float psfmin;
992 :
993 0 : minMax(psfmin, psfmax, psfposmin, psfposmax, lpsf);
994 :
995 0 : xpos=psfposmax(0);
996 0 : ypos=psfposmax(1);
997 :
998 :
999 :
1000 0 : amp=lpsf(xpos,ypos);
1001 :
1002 0 : ++psfli;
1003 0 : --nchan;
1004 : }
1005 :
1006 0 : }
1007 :
1008 0 : void StokesImageUtil::directCFromR(ImageInterface<Complex>& out, const ImageInterface<Float>& in) {
1009 0 : AlwaysAssert(in.shape()(0)==out.shape()(0), AipsError);
1010 0 : AlwaysAssert(in.shape()(1)==out.shape()(1), AipsError);
1011 0 : AlwaysAssert(in.shape()(3)==out.shape()(3), AipsError);
1012 :
1013 0 : Vector<Int> inmap;
1014 0 : AlwaysAssert(StokesMap(inmap, in.coordinates()), AipsError);
1015 0 : Vector<Int> outmap;
1016 0 : AlwaysAssert(StokesMap(outmap, out.coordinates()), AipsError);
1017 :
1018 0 : Int innpol = in.shape()(inmap(2));
1019 0 : Int outnpol = out.shape()(outmap(2));
1020 0 : if(innpol != outnpol){
1021 0 : throw(AipsError("Cannot convert directly between images of different polarization shape"));
1022 : }
1023 0 : Vector<Int> inMap(innpol), outMap(outnpol);
1024 : StokesImageUtil::PolRep outPolFrame;
1025 0 : Int nStokesOut=CStokesPolMap(outMap, outPolFrame, out.coordinates());
1026 : StokesImageUtil::PolRep inPolFrame;
1027 0 : Int nStokesIn=CStokesPolMap(inMap, inPolFrame, in.coordinates());
1028 0 : AlwaysAssert(nStokesOut, AipsError);
1029 0 : AlwaysAssert(nStokesIn, AipsError);
1030 :
1031 0 : if(inPolFrame != outPolFrame){
1032 0 : throw(AipsError("Cannot convert directly between polarization types"));
1033 : }
1034 0 : IPosition inblc(4,0,0,0,0);
1035 0 : IPosition intrc(4,0,0,0,0);
1036 0 : intrc(inmap(0))=in.shape()(inmap(0))-1;
1037 0 : intrc(inmap(1))=in.shape()(inmap(1))-1;
1038 0 : intrc(inmap(2))=0;
1039 0 : intrc(inmap(3))= in.shape()(inmap(3))-1;
1040 0 : IPosition outblc(4,0,0,0,0);
1041 0 : IPosition outtrc(4,0,0,0,0);
1042 0 : outtrc(outmap(0))=in.shape()(outmap(0))-1;
1043 0 : outtrc(outmap(1))=in.shape()(outmap(1))-1;
1044 0 : outtrc(outmap(2))=0;
1045 0 : outtrc(outmap(3))= in.shape()(outmap(3))-1;
1046 :
1047 0 : for (Int k=0; k < innpol ; ++k){
1048 0 : inblc(inmap(2))=k;
1049 0 : intrc(inmap(2))=k;
1050 0 : Int outindex=-1;
1051 0 : for ( Int j=0; j < innpol; ++j){
1052 0 : if(inMap[k]==outMap[j])
1053 0 : outindex=j;
1054 : }
1055 0 : if(outindex < 0){
1056 0 : throw(AipsError("cannot match polarization in direct copy"));
1057 : }
1058 0 : outblc(outmap(2))=outindex;
1059 0 : outtrc(outmap(2))=outindex;
1060 0 : Slicer slin(inblc, intrc, Slicer::endIsLast);
1061 0 : Slicer slout(outblc, outtrc, Slicer::endIsLast);
1062 0 : SubImage<Complex> sliceout(out, slout, true);
1063 0 : SubImage<Float> slicein(in, slin);
1064 0 : sliceout.copyData(LatticeExpr<Complex>(toComplex(slicein)));
1065 : }
1066 :
1067 :
1068 :
1069 :
1070 0 : }
1071 :
1072 0 : void StokesImageUtil::directCToR(ImageInterface<Float>& out, ImageInterface<Complex>& in) {
1073 0 : AlwaysAssert(in.shape()(0)==out.shape()(0), AipsError);
1074 0 : AlwaysAssert(in.shape()(1)==out.shape()(1), AipsError);
1075 0 : AlwaysAssert(in.shape()(3)==out.shape()(3), AipsError);
1076 :
1077 0 : Vector<Int> inmap;
1078 0 : AlwaysAssert(StokesMap(inmap, in.coordinates()), AipsError);
1079 0 : Vector<Int> outmap;
1080 0 : AlwaysAssert(StokesMap(outmap, out.coordinates()), AipsError);
1081 :
1082 0 : Int innpol = in.shape()(inmap(2));
1083 0 : Int outnpol = out.shape()(outmap(2));
1084 0 : if(innpol != outnpol){
1085 0 : throw(AipsError("Cannot convert directly between images of different polarization shape"));
1086 : }
1087 0 : Vector<Int> inMap(innpol), outMap(outnpol);
1088 : StokesImageUtil::PolRep outPolFrame;
1089 0 : Int nStokesOut=CStokesPolMap(outMap, outPolFrame, out.coordinates());
1090 : StokesImageUtil::PolRep inPolFrame;
1091 0 : Int nStokesIn=CStokesPolMap(inMap, inPolFrame, in.coordinates());
1092 :
1093 :
1094 0 : AlwaysAssert(nStokesOut, AipsError);
1095 0 : AlwaysAssert(nStokesIn, AipsError);
1096 0 : if(inPolFrame != outPolFrame){
1097 0 : throw(AipsError("Cannot convert directly between polarization types"));
1098 : }
1099 0 : IPosition inblc(4,0,0,0,0);
1100 0 : IPosition intrc(4,0,0,0,0);
1101 0 : intrc(inmap(0))=in.shape()(inmap(0))-1;
1102 0 : intrc(inmap(1))=in.shape()(inmap(1))-1;
1103 0 : intrc(inmap(2))=0;
1104 0 : intrc(inmap(3))= in.shape()(inmap(3))-1;
1105 0 : IPosition outblc(4,0,0,0,0);
1106 0 : IPosition outtrc(4,0,0,0,0);
1107 0 : outtrc(outmap(0))=in.shape()(outmap(0))-1;
1108 0 : outtrc(outmap(1))=in.shape()(outmap(1))-1;
1109 0 : outtrc(outmap(2))=0;
1110 0 : outtrc(outmap(3))= in.shape()(outmap(3))-1;
1111 :
1112 0 : for (Int k=0; k < innpol ; ++k){
1113 0 : inblc(inmap(2))=k;
1114 0 : intrc(inmap(2))=k;
1115 0 : Int outindex=-1;
1116 0 : for ( Int j=0; j < innpol; ++j){
1117 0 : if(inMap[k]==outMap[j])
1118 0 : outindex=j;
1119 : }
1120 0 : if(outindex < 0){
1121 0 : throw(AipsError("cannot match polarization in direct copy"));
1122 : }
1123 0 : outblc(outmap(2))=outindex;
1124 0 : outtrc(outmap(2))=outindex;
1125 0 : Slicer slin(inblc, intrc, Slicer::endIsLast);
1126 0 : Slicer slout(outblc, outtrc, Slicer::endIsLast);
1127 0 : SubImage<Float> sliceout(out, slout, true);
1128 0 : SubImage<Complex> slicein(in, slin);
1129 0 : sliceout.copyData(LatticeExpr<Float>(real(slicein)));
1130 : }
1131 :
1132 :
1133 0 : }
1134 :
1135 0 : void StokesImageUtil::To(ImageInterface<Float>& out, ImageInterface<Complex>& in) {
1136 :
1137 0 : AlwaysAssert(in.shape()(0)==out.shape()(0), AipsError);
1138 0 : AlwaysAssert(in.shape()(1)==out.shape()(1), AipsError);
1139 0 : AlwaysAssert(in.shape()(3)==out.shape()(3), AipsError);
1140 :
1141 0 : Vector<Int> map;
1142 0 : AlwaysAssert(StokesMap(map, in.coordinates()), AipsError);
1143 0 : Vector<Int> outmap;
1144 0 : AlwaysAssert(StokesMap(outmap, out.coordinates()), AipsError);
1145 :
1146 0 : Int nx = in.shape()(map(0));
1147 0 : Int innpol = in.shape()(map(2));
1148 0 : Int outnpol = out.shape()(outmap(2));
1149 :
1150 : // Loop over all planes
1151 0 : LatticeStepper inls(in.shape(), IPosition(4, nx, 1, innpol, 1),
1152 0 : IPosition(4, map(0), map(2), map(1), map(3)));
1153 0 : LatticeStepper outls(out.shape(), IPosition(4, nx, 1, outnpol, 1),
1154 0 : IPosition(4, map(0), map(2), map(1), map(3)));
1155 0 : RO_LatticeIterator<Complex> inli(in, inls);
1156 0 : LatticeIterator<Float> outli(out, outls);
1157 :
1158 0 : Vector<Int> inMap(innpol), outMap(outnpol);
1159 0 : StokesImageUtil::PolRep polFrame=StokesImageUtil::CIRCULAR;
1160 0 : Int nStokesIn=CStokesPolMap(inMap, polFrame, in.coordinates());
1161 0 : Int nStokesOut=StokesPolMap(outMap, out.coordinates());
1162 :
1163 0 : if(nStokesOut <=0){
1164 0 : directCToR(out, in);
1165 0 : return;
1166 : }
1167 0 : AlwaysAssert(nStokesOut, AipsError);
1168 : // Try taking real part only (uses LatticeExpr)
1169 0 : if(nStokesIn==0) {
1170 0 : nStokesIn=StokesPolMap(inMap, in.coordinates());
1171 0 : if(nStokesIn==nStokesOut) {
1172 0 : outli=LatticeIterator<Float> (out, inls);
1173 : //replaced copyData with iteration as it seems to load the whole array in memory
1174 0 : for (inli.reset(), outli.reset(); !inli.atEnd() && !outli.atEnd();
1175 0 : inli++,outli++) {
1176 0 : outli.woCursor()=real(inli.cursor());
1177 :
1178 : }
1179 :
1180 :
1181 : // out.copyData(LatticeExpr<Float>(real(in)));
1182 0 : return;
1183 : }
1184 0 : throw(AipsError("Illegal conversion in ToStokesImage"));
1185 : }
1186 :
1187 0 : Vector<Complex> cs(4);
1188 0 : cs=Complex(0.0);
1189 0 : CStokesVector csv(0.0, 0.0, 0.0, 0.0);
1190 0 : StokesVector sv(0.0, 0.0, 0.0, 0.0);
1191 : Int pol;
1192 0 : if(nStokesIn==1) {
1193 0 : for (inli.reset(), outli.reset(); !inli.atEnd() && !outli.atEnd();
1194 0 : inli++,outli++) {
1195 0 : for (Int ix=0;ix<nx;ix++) {
1196 0 : cs(inMap(0))=inli.vectorCursor()(ix);
1197 0 : csv=CStokesVector(cs(0), cs(1), cs(2), cs(3));
1198 0 : if(polFrame==StokesImageUtil::LINEAR) {
1199 0 : applySlinInv(sv, csv);
1200 : }
1201 : else {
1202 0 : applyScircInv(sv, csv);
1203 : }
1204 0 : if(nStokesOut==1) {
1205 0 : outli.rwVectorCursor()(ix)=sv(outMap(0));
1206 : }
1207 : else {
1208 0 : for (pol=0;pol<outnpol;pol++)
1209 0 : outli.rwMatrixCursor()(ix,pol)=sv(outMap(pol));
1210 : }
1211 : }
1212 : }
1213 : }
1214 : else {
1215 0 : for (inli.reset(), outli.reset(); !inli.atEnd() && !outli.atEnd(); inli++,outli++) {
1216 0 : for (Int ix=0;ix<nx;ix++) {
1217 0 : cs=Complex(0.0);
1218 0 : for (pol=0;pol<innpol;pol++) cs(inMap(pol))=inli.matrixCursor()(ix,pol);
1219 0 : csv=CStokesVector(cs(0), cs(1), cs(2), cs(3));
1220 0 : if(polFrame==StokesImageUtil::LINEAR) {
1221 0 : applySlinInv(sv, csv);
1222 : }
1223 : else {
1224 0 : applyScircInv(sv, csv);
1225 : }
1226 0 : if(nStokesOut==1) {
1227 0 : outli.rwVectorCursor()(ix)=sv(outMap(0));
1228 : }
1229 : else {
1230 0 : for (pol=0;pol<outnpol;pol++) {
1231 0 : outli.rwMatrixCursor()(ix,pol)=sv(outMap(pol));
1232 : }
1233 : }
1234 : }
1235 : }
1236 : }
1237 : };
1238 :
1239 0 : void StokesImageUtil::ToStokesPSF(ImageInterface<Float>& out, ImageInterface<Complex>& in) {
1240 :
1241 0 : AlwaysAssert(in.shape()(0)==out.shape()(0), AipsError);
1242 0 : AlwaysAssert(in.shape()(1)==out.shape()(1), AipsError);
1243 0 : AlwaysAssert(in.shape()(3)==out.shape()(3), AipsError);
1244 :
1245 0 : Vector<Int> map;
1246 0 : AlwaysAssert(StokesMap(map, in.coordinates()), AipsError);
1247 0 : Vector<Int> outmap;
1248 0 : AlwaysAssert(StokesMap(outmap, out.coordinates()), AipsError);
1249 :
1250 0 : Int nx = in.shape()(map(0));
1251 0 : Int innpol = in.shape()(map(2));
1252 0 : Int outnpol = out.shape()(outmap(2));
1253 :
1254 : // Loop over all planes
1255 0 : LatticeStepper inls(in.shape(), IPosition(4, nx, 1, innpol, 1),
1256 0 : IPosition(4, map(0), map(2), map(1), map(3)));
1257 0 : LatticeStepper outls(out.shape(), IPosition(4, nx, 1, outnpol, 1),
1258 0 : IPosition(4, map(0), map(2), map(1), map(3)));
1259 0 : RO_LatticeIterator<Complex> inli(in, inls);
1260 0 : LatticeIterator<Float> outli(out, outls);
1261 :
1262 0 : Vector<Int> inMap(innpol), outMap(outnpol);
1263 0 : StokesImageUtil::PolRep polFrame=StokesImageUtil::CIRCULAR;
1264 0 : Int nStokesIn=CStokesPolMap(inMap, polFrame, in.coordinates());
1265 0 : Int nStokesOut=StokesPolMap(outMap, out.coordinates());
1266 0 : if(nStokesOut <=0){
1267 0 : directCToR(out, in);
1268 0 : return;
1269 : }
1270 0 : AlwaysAssert(nStokesOut, AipsError);
1271 : // Try taking real part only (uses LatticeExpr)
1272 0 : if(nStokesIn==0) {
1273 0 : nStokesIn=StokesPolMap(inMap, in.coordinates());
1274 0 : if(nStokesIn==nStokesOut) {
1275 : //replaced copyData with iteration as it seems to load the whole array in memory
1276 0 : outli=LatticeIterator<Float> (out, inls);
1277 0 : for (inli.reset(), outli.reset(); !inli.atEnd() && !outli.atEnd();
1278 0 : inli++,outli++) {
1279 0 : outli.woCursor()=real(inli.cursor());
1280 :
1281 : }
1282 :
1283 : //out.copyData(LatticeExpr<Float>(real(in)));
1284 0 : return;
1285 : }
1286 0 : throw(AipsError("Illegal conversion in ToStokesImage"));
1287 : }
1288 :
1289 : /* STOKESDBG */ //cout << "ToStokesPSF - nstokesIn : " << nStokesIn << " inmap : " << inMap << " nstokesOut : " << nStokesOut << " outmap : " << outMap << endl;
1290 : /* STOKESDBG */ //cout << "IN (data) stokesCoord : " << ( (in.coordinates()).stokesCoordinate( (in.coordinates()).findCoordinate(Coordinate::STOKES) ) ).stokes() << " OUT (image) stokesCoord : " << ( (out.coordinates()).stokesCoordinate( (out.coordinates()).findCoordinate(Coordinate::STOKES) ) ).stokes() << endl;
1291 :
1292 0 : Vector<Int> inST = ( (in.coordinates()).stokesCoordinate( (in.coordinates()).findCoordinate(Coordinate::STOKES) ) ).stokes();
1293 0 : Vector<Int> outST = ( (out.coordinates()).stokesCoordinate( (out.coordinates()).findCoordinate(Coordinate::STOKES) ) ).stokes();
1294 :
1295 0 : Vector<Complex> cs(4);
1296 0 : cs=Complex(0.0);
1297 0 : CStokesVector csv(0.0, 0.0, 0.0, 0.0);
1298 0 : StokesVector sv(0.0, 0.0, 0.0, 0.0);
1299 : Int pol;
1300 0 : if(nStokesIn==1) {
1301 0 : for (inli.reset(), outli.reset(); !inli.atEnd() && !outli.atEnd();
1302 0 : inli++,outli++) {
1303 0 : for (Int ix=0;ix<nx;ix++) {
1304 0 : cs(inMap(0))=inli.vectorCursor()(ix);
1305 0 : csv=CStokesVector(cs(0), cs(1), cs(2), cs(3));
1306 0 : if(polFrame==StokesImageUtil::LINEAR) {
1307 0 : applySlinInv(sv, csv);
1308 : }
1309 : else {
1310 0 : applyScircInv(sv, csv);
1311 : }
1312 : // nstokesout will be 1, 2 or 4 only.
1313 0 : if(nStokesOut==1) {
1314 : //outli.rwVectorCursor()(ix)=sv(0); //sv(outMap(0));
1315 : // If outstokescoord = I or Q, use (I:0) : XX+YY for the PSF
1316 : // If outstokescoord = U or V, use (U:2) : XY+YX for the PSF
1317 0 : if( polFrame==StokesImageUtil::LINEAR )
1318 : {
1319 0 : if(Stokes::type(outST[0])==Stokes::I || Stokes::type(outST[0])==Stokes::Q )
1320 0 : outli.rwVectorCursor()(ix)=sv(0);
1321 0 : if( Stokes::type(outST[0])==Stokes::U || Stokes::type(outST[0])==Stokes::V )
1322 0 : outli.rwVectorCursor()(ix)=sv(2);
1323 : }
1324 0 : if( polFrame==StokesImageUtil::CIRCULAR )
1325 : {
1326 0 : if(Stokes::type(outST[0])==Stokes::I || Stokes::type(outST[0])==Stokes::V )
1327 0 : outli.rwVectorCursor()(ix)=sv(0);
1328 0 : if( Stokes::type(outST[0])==Stokes::Q || Stokes::type(outST[0])==Stokes::U )
1329 0 : outli.rwVectorCursor()(ix)=sv(1);
1330 : }
1331 : }
1332 0 : else if(nStokesOut==2) {
1333 : // If outstokescoord = IQ, use (I:0) : XX+YY for the PSF in both planes
1334 : // If outstokescoord = UV, use (U:2) : XY+YX for the PSF in both planes
1335 0 : if( polFrame==StokesImageUtil::LINEAR )
1336 : {
1337 0 : if(Stokes::type(outST[0])==Stokes::I || Stokes::type(outST[0])==Stokes::Q ||
1338 0 : Stokes::type(outST[1])==Stokes::I || Stokes::type(outST[1])==Stokes::Q )
1339 0 : { outli.rwMatrixCursor()(ix,0)=sv(0); outli.rwMatrixCursor()(ix,1)=sv(0); }
1340 0 : if( Stokes::type(outST[0])==Stokes::U || Stokes::type(outST[0])==Stokes::V ||
1341 0 : Stokes::type(outST[1])==Stokes::U || Stokes::type(outST[1])==Stokes::V )
1342 0 : { outli.rwMatrixCursor()(ix,0)=sv(2); outli.rwMatrixCursor()(ix,1)=sv(2); }
1343 : }
1344 0 : if( polFrame==StokesImageUtil::CIRCULAR )
1345 : {
1346 0 : if(Stokes::type(outST[0])==Stokes::I || Stokes::type(outST[0])==Stokes::V ||
1347 0 : Stokes::type(outST[1])==Stokes::I || Stokes::type(outST[1])==Stokes::V )
1348 0 : { outli.rwMatrixCursor()(ix,0)=sv(0); outli.rwMatrixCursor()(ix,1)=sv(0); }
1349 0 : if( Stokes::type(outST[0])==Stokes::Q || Stokes::type(outST[0])==Stokes::U ||
1350 0 : Stokes::type(outST[1])==Stokes::Q || Stokes::type(outST[1])==Stokes::U )
1351 0 : { outli.rwMatrixCursor()(ix,0)=sv(1); outli.rwMatrixCursor()(ix,1)=sv(1); }
1352 : }
1353 : }
1354 : else { // nstokesout = 4 : do a one-to-one mapping.
1355 0 : for (pol=0;pol<outnpol;pol++)
1356 0 : outli.rwMatrixCursor()(ix,pol)=sv(outMap(pol));
1357 : }
1358 : }
1359 : }
1360 : }
1361 : else {
1362 0 : for (inli.reset(), outli.reset(); !inli.atEnd() && !outli.atEnd(); inli++,outli++) {
1363 0 : for (Int ix=0;ix<nx;ix++) {
1364 0 : cs=Complex(0.0);
1365 0 : for (pol=0;pol<innpol;pol++) cs(inMap(pol))=inli.matrixCursor()(ix,pol);
1366 0 : csv=CStokesVector(cs(0), cs(1), cs(2), cs(3));
1367 0 : if(polFrame==StokesImageUtil::LINEAR) {
1368 0 : applySlinInv(sv, csv);
1369 : }
1370 : else {
1371 0 : applyScircInv(sv, csv);
1372 : }
1373 0 : if(nStokesOut==1) {
1374 : //outli.rwVectorCursor()(ix)=sv(0); //sv(outMap(0));
1375 : // If outstokescoord = I or Q, use (I:0)
1376 : // If outstokescoord = U or V, use (U:2)
1377 0 : if( polFrame==StokesImageUtil::LINEAR )
1378 : {
1379 0 : if(Stokes::type(outST[0])==Stokes::I || Stokes::type(outST[0])==Stokes::Q )
1380 0 : outli.rwVectorCursor()(ix)=sv(0);
1381 0 : if( Stokes::type(outST[0])==Stokes::U || Stokes::type(outST[0])==Stokes::V )
1382 0 : outli.rwVectorCursor()(ix)=sv(2);
1383 : }
1384 0 : if( polFrame==StokesImageUtil::CIRCULAR )
1385 : {
1386 0 : if(Stokes::type(outST[0])==Stokes::I || Stokes::type(outST[0])==Stokes::V )
1387 0 : outli.rwVectorCursor()(ix)=sv(0);
1388 0 : if( Stokes::type(outST[0])==Stokes::Q || Stokes::type(outST[0])==Stokes::U )
1389 0 : outli.rwVectorCursor()(ix)=sv(1);
1390 : }
1391 : }
1392 0 : else if(nStokesOut==2) {
1393 : // If outstokescoord = IQ, use (I:0) : XX+YY for the PSF in both planes
1394 : // If outstokescoord = UV, use (U:2) : XY+YX for the PSF in both planes
1395 0 : if( polFrame==StokesImageUtil::LINEAR )
1396 : {
1397 0 : if(Stokes::type(outST[0])==Stokes::I || Stokes::type(outST[0])==Stokes::Q ||
1398 0 : Stokes::type(outST[1])==Stokes::I || Stokes::type(outST[1])==Stokes::Q )
1399 0 : { outli.rwMatrixCursor()(ix,0)=sv(0); outli.rwMatrixCursor()(ix,1)=sv(0); }
1400 0 : if( Stokes::type(outST[0])==Stokes::U || Stokes::type(outST[0])==Stokes::V ||
1401 0 : Stokes::type(outST[1])==Stokes::U || Stokes::type(outST[1])==Stokes::V )
1402 0 : { outli.rwMatrixCursor()(ix,0)=sv(2); outli.rwMatrixCursor()(ix,1)=sv(2); }
1403 : }
1404 0 : if( polFrame==StokesImageUtil::CIRCULAR )
1405 : {
1406 0 : if(Stokes::type(outST[0])==Stokes::I || Stokes::type(outST[0])==Stokes::V ||
1407 0 : Stokes::type(outST[1])==Stokes::I || Stokes::type(outST[1])==Stokes::V )
1408 0 : { outli.rwMatrixCursor()(ix,0)=sv(0); outli.rwMatrixCursor()(ix,1)=sv(0); }
1409 0 : if( Stokes::type(outST[0])==Stokes::Q || Stokes::type(outST[0])==Stokes::U ||
1410 0 : Stokes::type(outST[1])==Stokes::Q || Stokes::type(outST[1])==Stokes::U )
1411 0 : { outli.rwMatrixCursor()(ix,0)=sv(1); outli.rwMatrixCursor()(ix,1)=sv(1); }
1412 : }
1413 : }
1414 : else { // nstokesout = 4
1415 0 : for (pol=0;pol<outnpol;pol++) {
1416 0 : outli.rwMatrixCursor()(ix,pol)=sv(outMap(0));
1417 : }
1418 : }
1419 : }
1420 : }
1421 : }
1422 : };
1423 :
1424 0 : void StokesImageUtil::ToStokesSumWt(Matrix<Float> sumwtStokes, Matrix<Float> sumwtCorr, const CoordinateSystem& outcoord, const CoordinateSystem& incoord)
1425 : {
1426 :
1427 0 : AlwaysAssert( sumwtStokes.shape()[1] == sumwtCorr.shape()(1) , AipsError );
1428 0 : Vector<Int> inmap;
1429 0 : AlwaysAssert(StokesMap(inmap, incoord), AipsError);
1430 0 : Vector<Int> outmap;
1431 0 : AlwaysAssert(StokesMap(outmap, outcoord), AipsError);
1432 :
1433 :
1434 0 : Int innpol = sumwtCorr.shape()[0];
1435 0 : Int outnpol = sumwtStokes.shape()[0];
1436 :
1437 :
1438 0 : Vector<Int> inMap(innpol), outMap(outnpol);
1439 0 : StokesImageUtil::PolRep polFrame=StokesImageUtil::CIRCULAR;
1440 0 : Int nStokesIn=CStokesPolMap(inMap, polFrame, incoord);
1441 0 : Int nStokesOut=StokesPolMap(outMap, outcoord);
1442 0 : if(nStokesOut <=0 || nStokesIn==0) {
1443 0 : if(innpol != outnpol)
1444 0 : throw(AipsError("Cannot copy sumwt as input and output have different pol axis length"));
1445 0 : convertArray(sumwtStokes, sumwtCorr);
1446 0 : return;
1447 : }
1448 0 : if( nStokesOut==1 && nStokesIn==2){
1449 :
1450 0 : for(uInt chan=0;chan<sumwtStokes.shape()[1];chan++)
1451 : {
1452 0 : sumwtStokes(0,chan) = min(sumwtCorr(0,chan),sumwtCorr(1, chan));
1453 : }
1454 : }
1455 0 : if( nStokesOut==2 && nStokesIn==2){
1456 :
1457 0 : for(uInt chan=0;chan<sumwtStokes.shape()[1];chan++)
1458 : {
1459 0 : sumwtStokes(0,chan) = min(sumwtCorr(0,chan),sumwtCorr(1, chan));
1460 0 : sumwtStokes(1,chan) = min(sumwtCorr(1,chan),sumwtCorr(1, chan));
1461 : }
1462 : }
1463 0 : if( nStokesOut==4 && nStokesIn==4){
1464 :
1465 0 : for(uInt chan=0;chan<sumwtStokes.shape()[1];chan++)
1466 : {
1467 0 : if(polFrame==StokesImageUtil::LINEAR){
1468 0 : sumwtStokes(0,chan) = min(sumwtCorr(0,chan),sumwtCorr(3, chan));
1469 0 : sumwtStokes(1,chan) = min(sumwtCorr(0,chan),sumwtCorr(3, chan));
1470 0 : sumwtStokes(2,chan) = min(sumwtCorr(1,chan),sumwtCorr(2, chan));
1471 0 : sumwtStokes(3,chan) = min(sumwtCorr(1,chan),sumwtCorr(2, chan));
1472 : }
1473 : else{
1474 0 : sumwtStokes(0,chan) = min(sumwtCorr(0,chan),sumwtCorr(3, chan));
1475 0 : sumwtStokes(1,chan) = min(sumwtCorr(1,chan),sumwtCorr(2, chan));
1476 0 : sumwtStokes(2,chan) = min(sumwtCorr(1,chan),sumwtCorr(2, chan));
1477 0 : sumwtStokes(3,chan) = min(sumwtCorr(0,chan),sumwtCorr(3, chan));
1478 : }
1479 : }
1480 : }
1481 :
1482 :
1483 : }
1484 :
1485 0 : void StokesImageUtil::ToStokesSumWt(Matrix<Float> sumwtStokes, Matrix<Float> sumwtCorr)
1486 : {
1487 0 : AlwaysAssert( sumwtStokes.shape()[1] == sumwtCorr.shape()(1) , AipsError ); //same nchan
1488 0 : AlwaysAssert( sumwtCorr.shape()[0] > 0, AipsError ); // at least one correlation gridded.
1489 :
1490 : /// Pick the value from the first correlation plane, and fill it into all stokes planes.
1491 : /// This is valid when the same weights are used across correlations.
1492 0 : for(uInt pol=0;pol<sumwtStokes.shape()[0];pol++)
1493 : {
1494 0 : for(uInt chan=0;chan<sumwtStokes.shape()[1];chan++)
1495 : {
1496 0 : sumwtStokes(pol,chan) = sumwtCorr(0,chan);
1497 : }
1498 : }
1499 :
1500 0 : }
1501 :
1502 :
1503 : #if 0
1504 : void StokesImageUtil::ToStokesPSF(ImageInterface<Float>& out, ImageInterface<Complex>& in) {
1505 :
1506 : AlwaysAssert(in.shape()(0)==out.shape()(0), AipsError);
1507 : AlwaysAssert(in.shape()(1)==out.shape()(1), AipsError);
1508 : AlwaysAssert(out.shape()(2)==out.shape()(3), AipsError);
1509 : AlwaysAssert(in.shape()(3)==out.shape()(4), AipsError);
1510 :
1511 : Vector<Int> map;
1512 : AlwaysAssert(StokesMap(map, in.coordinates()), AipsError);
1513 : Vector<Int> outmap;
1514 : AlwaysAssert(StokesMap(outmap, out.coordinates()), AipsError);
1515 :
1516 : Int nx = in.shape()(map(0));
1517 : Int innpol = in.shape()(map(2));
1518 : Int outnpol = out.shape()(outmap(2));
1519 :
1520 : // Loop over all planes. For the input we get a line of complex pixels
1521 : // for the output we put a line of float matrices
1522 : LatticeStepper inls(in.shape(), IPosition(4, nx, 1, innpol, 1),
1523 : IPosition(4, map(0), map(2), map(1), map(3)));
1524 : LatticeStepper outls(out.shape(), IPosition(5, nx, 1, outnpol, outnpol, 1),
1525 : IPosition(5, map(0), map(3), map(1), map(2), 4));
1526 : RO_LatticeIterator<Complex> inli(in, inls);
1527 : LatticeIterator<Float> outli(out, outls);
1528 :
1529 : Vector<Int> inMap(innpol), outMap(outnpol);
1530 : StokesImageUtil::PolRep polFrame;
1531 : Int nStokesIn=CStokesPolMap(inMap, polFrame, in.coordinates());
1532 : AlwaysAssert(nStokesIn, AipsError);
1533 : Int nStokesOut=StokesPolMap(outMap, out.coordinates());
1534 : AlwaysAssert(nStokesOut, AipsError);
1535 :
1536 : Matrix<Complex> s(4,4), sAdjoint(4,4);
1537 : s=0;
1538 : if(polFrame==StokesImageUtil::LINEAR) {
1539 : s(0,0)=Complex(0.5);
1540 : s(0,1)=Complex(0.5);
1541 : s(1,2)=Complex(0.5);
1542 : s(1,3)=Complex(0.0,0.5);
1543 : s(2,2)=Complex(0.5);
1544 : s(2,3)=Complex(0.0,-0.5);
1545 : s(3,0)=Complex(0.5);
1546 : s(3,1)=Complex(-0.5);
1547 : }
1548 : else {
1549 : s(0,0)=Complex(0.5);
1550 : s(0,3)=Complex(0.5);
1551 : s(1,1)=Complex(0.5);
1552 : s(1,2)=Complex(0.0,0.5);
1553 : s(2,1)=Complex(0.5);
1554 : s(2,2)=Complex(0.0,-0.5);
1555 : s(3,0)=Complex(0.5);
1556 : s(3,3)=Complex(-0.5);
1557 : }
1558 : sAdjoint=adjoint(s);
1559 :
1560 : Matrix<Complex> lambda(4,4);
1561 : lambda=Complex(0.0);
1562 :
1563 : Matrix<Float> stokesPSF(4,4);
1564 : Int i, j;
1565 : for (inli.reset(), outli.reset(); !inli.atEnd() && !outli.atEnd(); inli++,outli++) {
1566 : for (Int ix=0;ix<nx;ix++) {
1567 : // Get the channel
1568 : // Fill in the weight vector
1569 : if(innpol==1) {
1570 : lambda(inMap(0),inMap(0))=inli.vectorCursor()(ix);
1571 : }
1572 : else {
1573 : for (i=0;i<innpol;i++) lambda(inMap(i),inMap(i))=
1574 : inli.matrixCursor()(ix,i);
1575 : }
1576 : stokesPSF=real(product(s,product(lambda, sAdjoint)));
1577 : if(nStokesOut==1) {
1578 : outli.rwVectorCursor()(ix)=stokesPSF(outMap(0),outMap(0));
1579 : }
1580 : else {
1581 : for (j=0;j<outnpol;j++) {
1582 : for (i=0;i<outnpol;i++) {
1583 : outli.rwCubeCursor()(ix,i,j)=stokesPSF(outMap(i),outMap(j));
1584 : }
1585 : }
1586 : }
1587 : }
1588 : }
1589 : };
1590 : #endif
1591 :
1592 0 : void StokesImageUtil::From(ImageInterface<Complex>& out,
1593 : const ImageInterface<Float>& in) {
1594 :
1595 0 : AlwaysAssert(in.shape()(0)==out.shape()(0), AipsError);
1596 0 : AlwaysAssert(in.shape()(1)==out.shape()(1), AipsError);
1597 0 : AlwaysAssert(in.shape()(3)==out.shape()(3), AipsError);
1598 :
1599 :
1600 0 : Vector<Int> map;
1601 0 : AlwaysAssert(StokesMap(map, in.coordinates()), AipsError);
1602 0 : Vector<Int> outmap;
1603 0 : AlwaysAssert(StokesMap(outmap, out.coordinates()), AipsError);
1604 :
1605 0 : Int nx = in.shape()(map(0));
1606 0 : Int innpol = in.shape()(map(2));
1607 0 : Int outnpol = out.shape()(outmap(2));
1608 :
1609 0 : Vector<Int> inMap(innpol), outMap(outnpol);
1610 0 : StokesImageUtil::PolRep polFrame=StokesImageUtil::LINEAR;
1611 0 : Int nStokesIn=StokesPolMap(inMap, in.coordinates());
1612 0 : if(nStokesIn <=0){
1613 0 : directCFromR(out, in);
1614 0 : return;
1615 : }
1616 0 : AlwaysAssert(nStokesIn, AipsError);
1617 0 : Int nStokesOut=CStokesPolMap(outMap, polFrame, out.coordinates());
1618 0 : if(nStokesOut==0) {
1619 0 : nStokesOut=StokesPolMap(outMap, out.coordinates());
1620 0 : if(nStokesIn==nStokesOut) {
1621 0 : out.copyData(LatticeExpr<Complex>(toComplex(in)));
1622 0 : return;
1623 : }
1624 0 : throw(AipsError("Illegal conversion in FromStokesImage"));
1625 : }
1626 :
1627 : // Loop over all planes
1628 0 : LatticeStepper inls(in.shape(), IPosition(4, nx, 1, innpol, 1),
1629 0 : IPosition(4, map(0), map(2), map(1), map(3)));
1630 0 : LatticeStepper outls(out.shape(), IPosition(4, nx, 1, outnpol, 1),
1631 0 : IPosition(4, map(0), map(2), map(1), map(3)));
1632 0 : RO_LatticeIterator<Float> inli(in, inls);
1633 0 : LatticeIterator<Complex> outli(out, outls);
1634 :
1635 0 : Vector<Float> s(4);
1636 0 : CStokesVector csv(0.0, 0.0, 0.0, 0.0);
1637 0 : StokesVector sv(0.0, 0.0, 0.0, 0.0);
1638 : Int pol;
1639 0 : if(nStokesIn==1) {
1640 0 : for (inli.reset(), outli.reset(); !inli.atEnd() && !outli.atEnd(); inli++,outli++) {
1641 0 : for (Int ix=0;ix<nx;ix++) {
1642 0 : s=0.0;
1643 0 : s(inMap(0))=inli.vectorCursor()(ix);
1644 0 : sv=StokesVector(s(0), s(1), s(2), s(3));
1645 0 : if(polFrame==StokesImageUtil::LINEAR) {
1646 0 : applySlin(csv, sv);
1647 : }
1648 : else {
1649 0 : applyScirc(csv, sv);
1650 : }
1651 0 : if(nStokesOut==1) {
1652 0 : outli.rwVectorCursor()(ix)=csv(outMap(0));
1653 : }
1654 : else {
1655 0 : for (pol=0;pol<outnpol;pol++) {
1656 0 : outli.rwMatrixCursor()(ix,pol)=csv(outMap(pol));
1657 : }
1658 : }
1659 : }
1660 : }
1661 : }
1662 : else {
1663 0 : for (inli.reset(), outli.reset(); !inli.atEnd() && !outli.atEnd(); inli++,outli++) {
1664 0 : for (Int ix=0;ix<nx;ix++) {
1665 0 : s=0.0;
1666 0 : for(pol=0;pol<innpol;pol++) s(inMap(pol))=inli.matrixCursor()(ix,pol);
1667 0 : sv=StokesVector(s(0), s(1), s(2), s(3));
1668 0 : if(polFrame==StokesImageUtil::LINEAR) {
1669 0 : applySlin(csv, sv);
1670 : }
1671 : else {
1672 0 : applyScirc(csv, sv);
1673 : }
1674 0 : if(nStokesOut==1) {
1675 0 : outli.rwVectorCursor()(ix)=csv(outMap(0));
1676 : }
1677 : else {
1678 0 : for (pol=0;pol<outnpol;pol++) {
1679 0 : outli.rwMatrixCursor()(ix,pol)=csv(outMap(pol));
1680 : }
1681 : }
1682 : }
1683 : }
1684 : }
1685 : };
1686 :
1687 : // map(axis) is the polarization in the sequence I,Q,U,V
1688 : // This is the sequence used by StokesVector
1689 0 : Int StokesImageUtil::StokesPolMap(Vector<Int>& map, const CoordinateSystem& coord) {
1690 :
1691 0 : map=-1;
1692 : Int stokesIndex;
1693 0 : stokesIndex= coord.findCoordinate(Coordinate::STOKES);
1694 0 : StokesCoordinate stokesCoord=coord.stokesCoordinate(stokesIndex);
1695 : Int pol, p;
1696 0 : Bool Found= stokesCoord.toPixel(p, Stokes::I)||
1697 0 : stokesCoord.toPixel(p, Stokes::Q)||
1698 0 : stokesCoord.toPixel(p, Stokes::U)||
1699 0 : stokesCoord.toPixel(p, Stokes::V);
1700 0 : if(Found) {
1701 0 : pol=0;
1702 0 : Int found=0;
1703 0 : if(stokesCoord.toPixel(p, Stokes::I)) {map(p)=pol;found++;} pol++;
1704 0 : if(stokesCoord.toPixel(p, Stokes::Q)) {map(p)=pol;found++;} pol++;
1705 0 : if(stokesCoord.toPixel(p, Stokes::U)) {map(p)=pol;found++;} pol++;
1706 0 : if(stokesCoord.toPixel(p, Stokes::V)) {map(p)=pol;found++;} pol++;
1707 0 : return found;
1708 : }
1709 0 : return 0;
1710 : }
1711 :
1712 : // map(axis) is the polarization in the sequence XX,XY,YX,YY or RR,RL,LR,LL.
1713 : // This is the sequence used by CStokesVector
1714 0 : Int StokesImageUtil::CStokesPolMap(Vector<Int>& map, StokesImageUtil::PolRep& polFrame,
1715 : const CoordinateSystem& coord) {
1716 :
1717 0 : map=-1;
1718 : Int stokesIndex;
1719 0 : stokesIndex=coord.findCoordinate(Coordinate::STOKES);
1720 0 : StokesCoordinate stokesCoord=coord.stokesCoordinate(stokesIndex);
1721 : Int pol, p;
1722 0 : Int found=0;
1723 0 : Bool Linear= stokesCoord.toPixel(p, Stokes::XX)||
1724 0 : stokesCoord.toPixel(p, Stokes::XY)||
1725 0 : stokesCoord.toPixel(p, Stokes::YX)||
1726 0 : stokesCoord.toPixel(p, Stokes::YY);
1727 0 : if(Linear) {
1728 0 : pol=0;
1729 0 : if(stokesCoord.toPixel(p, Stokes::XX)) {map(p)=pol;found++;} pol++;
1730 0 : if(stokesCoord.toPixel(p, Stokes::XY)) {map(p)=pol;found++;} pol++;
1731 0 : if(stokesCoord.toPixel(p, Stokes::YX)) {map(p)=pol;found++;} pol++;
1732 0 : if(stokesCoord.toPixel(p, Stokes::YY)) {map(p)=pol;found++;} pol++;
1733 0 : polFrame=StokesImageUtil::LINEAR;
1734 0 : return found;
1735 : }
1736 0 : Bool Circular= stokesCoord.toPixel(p, Stokes::LL)||
1737 0 : stokesCoord.toPixel(p, Stokes::LR)||
1738 0 : stokesCoord.toPixel(p, Stokes::RL)||
1739 0 : stokesCoord.toPixel(p, Stokes::RR);
1740 :
1741 :
1742 0 : if(Circular) {
1743 0 : pol=0;
1744 0 : if(stokesCoord.toPixel(p, Stokes::RR)) {map(p)=pol;found++;} pol++;
1745 0 : if(stokesCoord.toPixel(p, Stokes::RL)) {map(p)=pol;found++;} pol++;
1746 0 : if(stokesCoord.toPixel(p, Stokes::LR)) {map(p)=pol;found++;} pol++;
1747 0 : if(stokesCoord.toPixel(p, Stokes::LL)) {map(p)=pol;found++;} pol++;
1748 0 : polFrame=StokesImageUtil::CIRCULAR;
1749 0 : return found;
1750 : }
1751 0 : return 0;
1752 : }
1753 :
1754 0 : CoordinateSystem StokesImageUtil::StokesCoordFromMS(const IPosition& shape, Vector<Double>& deltas,
1755 : MeasurementSet& ms) {
1756 0 : Vector<Int> whichStokes(0);
1757 0 : return StokesCoordFromMS(shape, deltas, ms, whichStokes);
1758 : }
1759 :
1760 0 : CoordinateSystem StokesImageUtil::StokesCoordFromMS(const IPosition& shape, Vector<Double>& deltas,
1761 : MeasurementSet& ms, Vector<Int>& whichStokes,
1762 : Bool doCStokes, Int fieldID, Int SPWID, Int feedID) {
1763 :
1764 0 : MSColumns msc(ms);
1765 :
1766 0 : Int nx=shape(0);
1767 0 : Int ny=shape(1);
1768 0 : Int npol=shape(2);
1769 0 : Int nchan=shape(3);
1770 :
1771 0 : Vector<Double> refCoord=msc.field().phaseDir()(fieldID);
1772 0 : Vector<Double> refPixel(2);
1773 0 : refPixel(0)=Double(nx/2);
1774 0 : refPixel(1)=Double(ny/2);
1775 :
1776 0 : Matrix<Double> xform(2,2);
1777 0 : xform=0.0;xform.diagonal()=1.0;
1778 : DirectionCoordinate myRaDec(MDirection::J2000,
1779 : Projection::SIN,
1780 0 : refCoord(0), refCoord(1),
1781 0 : deltas(0), deltas(1),
1782 : xform,
1783 0 : refPixel(0), refPixel(1));
1784 :
1785 : // Frequency
1786 0 : Vector<Double> chanFreq=msc.spectralWindow().chanFreq()(SPWID);
1787 0 : if(nchan==0) nchan=chanFreq.shape()(SPWID);
1788 0 : Double refChan=0.0;
1789 0 : Vector<Double> freqResolution=msc.spectralWindow().resolution()(SPWID);
1790 :
1791 : // Retrieve the first rest frequency used with this SPW_ID (for now)
1792 0 : MSDopplerUtil msdoppler(ms);
1793 0 : Vector<Double> restFreqArray;
1794 : Double restFreq;
1795 0 : if (msdoppler.dopplerInfo(restFreqArray,SPWID,fieldID)) {
1796 0 : restFreq=restFreqArray(0);
1797 : } else {
1798 0 : restFreq=1.0;
1799 : };
1800 :
1801 0 : SpectralCoordinate mySpectral(MFrequency::TOPO, chanFreq(0),
1802 0 : freqResolution(0), refChan,
1803 0 : restFreq);
1804 :
1805 : // Polarization: If the specified whichStokes are ok, we use them
1806 : // otherwise we guess
1807 0 : if(Int(whichStokes.nelements())!=npol) {
1808 0 : Vector<String> polType=msc.feed().polarizationType()(feedID);
1809 0 : whichStokes.resize(npol);
1810 : // Polarization
1811 0 : if(doCStokes) {
1812 0 : if (polType(0)=="X" || polType(0)=="Y") {
1813 0 : switch(npol) {
1814 0 : case 1:
1815 0 : whichStokes.resize(1);
1816 0 : whichStokes(0)=Stokes::I;
1817 0 : break;
1818 0 : case 2:
1819 0 : whichStokes.resize(2);
1820 0 : whichStokes(0)=Stokes::XX;
1821 0 : whichStokes(1)=Stokes::YY;
1822 0 : break;
1823 0 : default:
1824 0 : whichStokes.resize(4);
1825 0 : whichStokes(0)=Stokes::XX;
1826 0 : whichStokes(1)=Stokes::XY;
1827 0 : whichStokes(2)=Stokes::YX;
1828 0 : whichStokes(3)=Stokes::YY;
1829 : }
1830 : }
1831 : else {
1832 0 : switch(npol) {
1833 0 : case 1:
1834 0 : whichStokes.resize(1);
1835 0 : whichStokes(0)=Stokes::I;
1836 0 : break;
1837 0 : case 2:
1838 0 : whichStokes.resize(2);
1839 0 : whichStokes(0)=Stokes::LL;
1840 0 : whichStokes(1)=Stokes::RR;
1841 0 : break;
1842 0 : default:
1843 0 : whichStokes.resize(4);
1844 0 : whichStokes(0)=Stokes::LL;
1845 0 : whichStokes(1)=Stokes::LR;
1846 0 : whichStokes(2)=Stokes::RL;
1847 0 : whichStokes(3)=Stokes::RR;
1848 : };
1849 : }
1850 : }
1851 : else {
1852 0 : switch(npol) {
1853 0 : case 1:
1854 0 : whichStokes.resize(1);
1855 0 : whichStokes(0)=Stokes::I;
1856 0 : break;
1857 0 : case 2:
1858 0 : whichStokes.resize(2);
1859 0 : whichStokes(0)=Stokes::I;
1860 0 : if (polType(0)=="X" || polType(0)=="Y") {
1861 0 : whichStokes(1)=Stokes::Q;
1862 : }
1863 : else {
1864 0 : whichStokes(1)=Stokes::V;
1865 : }
1866 0 : break;
1867 0 : case 3:
1868 0 : whichStokes.resize(3);
1869 0 : whichStokes(0)=Stokes::I;
1870 0 : whichStokes(1)=Stokes::Q;
1871 0 : whichStokes(2)=Stokes::U;
1872 0 : break;
1873 0 : case 4:
1874 0 : whichStokes.resize(4);
1875 0 : whichStokes(0)=Stokes::I;
1876 0 : whichStokes(1)=Stokes::Q;
1877 0 : whichStokes(2)=Stokes::U;
1878 0 : whichStokes(3)=Stokes::V;
1879 0 : break;
1880 : };
1881 : }
1882 : }
1883 0 : StokesCoordinate myStokes(whichStokes);
1884 :
1885 : // Now set up coordinates for image. If the shape is
1886 : // 5 dimensional then we add another StokesCoordinate
1887 0 : CoordinateSystem coordInfo;
1888 0 : coordInfo.addCoordinate(myRaDec);
1889 0 : coordInfo.addCoordinate(myStokes);
1890 0 : if(shape.nelements()==5) coordInfo.addCoordinate(myStokes);
1891 0 : coordInfo.addCoordinate(mySpectral);
1892 0 : return coordInfo;
1893 :
1894 : }
1895 :
1896 : /* This function sets up the Stokes labelling for the polarization planes of
1897 : 'cImage', the complex image that stores gridded correlations.
1898 :
1899 : For example, if 'V' is asked for, we need to grid RR and LL (npol = 2 pol planes in cImage).
1900 :
1901 : Called from the first call of ImageStokesImageUtil::cImage().
1902 :
1903 : Input : shape = shape of cImage.
1904 : polRep : Circular or Linear - present in the data.
1905 : Input/Output : coords = Input polarization labelling is that of the target image ('V')
1906 : Output polarization labelling is for the correlations ('RR','LL').
1907 : whichStokes = empty on input (first time).
1908 : Fill in the data correlation labels ('RR', 'LL')
1909 :
1910 : */
1911 0 : CoordinateSystem StokesImageUtil::CStokesCoord(//const IPosition& shape,
1912 : const CoordinateSystem& coord,
1913 : Vector<Int>& whichStokes,
1914 : StokesImageUtil::PolRep polRep) {
1915 : /*
1916 : Int nx=shape(0);
1917 : Int ny=shape(1);
1918 : Int npol=shape(2);
1919 : Int nchan=shape(3);
1920 : AlwaysAssert(nx>0, AipsError);
1921 : AlwaysAssert(ny>0, AipsError);
1922 : AlwaysAssert(npol>0, AipsError);
1923 : AlwaysAssert(nchan>0, AipsError);
1924 : */
1925 :
1926 0 : Int directionIndex=coord.findCoordinate(Coordinate::DIRECTION);
1927 0 : DirectionCoordinate directionCoord=coord.directionCoordinate(directionIndex);
1928 :
1929 0 : Int spectralIndex=coord.findCoordinate(Coordinate::SPECTRAL);
1930 0 : SpectralCoordinate spectralCoord=coord.spectralCoordinate(spectralIndex);
1931 :
1932 0 : Int stokesIndex=coord.findCoordinate(Coordinate::STOKES);
1933 : StokesCoordinate
1934 0 : stokesCoord=coord.stokesCoordinate(stokesIndex);
1935 :
1936 : /* STOKESDBG */ //cout << "Util : CStokesCoord - input - stokesCoord : " << stokesCoord.stokes() << endl;
1937 :
1938 : // Polarization: If the specified whichStokes are ok, we use them
1939 : // if(Int(whichStokes.nelements())!=npol) {
1940 : // whichStokes.resize(npol);
1941 : // whichStokes=0;
1942 0 : changeLabelsStokesToCorrStokes(stokesCoord, polRep, whichStokes);
1943 : //}
1944 0 : AlwaysAssert(whichStokes.nelements(), AipsError);
1945 0 : StokesCoordinate stokesCoordOut(whichStokes);
1946 :
1947 : /* STOKESDBG */ //cout << "Util : CStokesCoord - output - stokesCoord : " << stokesCoordOut.stokes() << endl;
1948 :
1949 : // Now set up coordinates
1950 0 : CoordinateSystem coordInfo;
1951 0 : coordInfo.addCoordinate(directionCoord);
1952 0 : coordInfo.addCoordinate(stokesCoordOut);
1953 0 : coordInfo.addCoordinate(spectralCoord);
1954 0 : return coordInfo;
1955 :
1956 : }
1957 :
1958 : /*
1959 : Logic : Read the desired image stokes from "stokesCoord" : 'V'
1960 : Read the desired "npol" from the length of stokesCoord : '2'
1961 : For npol = 1,2,3,4, if any image-pol choice requires an explicit mapping
1962 : to correlations, resize 'whichStokes' accordingly, and fill in.
1963 : For example, 'V' is mapped to 'RR,LL' for Circular, and 'XY,YX' for Linear.
1964 : Finally, check that all correlations in 'whichStokes' are present in the data.
1965 :
1966 : Subsequent calls to this function -- which already have the input stokesCoord in the
1967 : correlation basis, will not do anything.
1968 :
1969 : Rules :
1970 : npol = 1 : I, XX,YY,XY,YX,RR,LL.RL,LR --- choose only one correlation
1971 : Q, U, V -- map to 2 correlations as required for Circular vs Linear
1972 : Note : "I" is a special-case for which ftmachines and gridders know how to use only one plane.
1973 : npol = 2 : RRLL,RLLR,XXYY,XYYX; IV,QU for Circular; IQ,UV for Linear -- map to 2 correlations
1974 : IV, QU for Linear; IQ,UV for Circular -- map to 4 correlations
1975 : npol = 3,4 : Choose all 4 correlations.
1976 :
1977 : 'whichStokes' contains the output
1978 : */
1979 0 : void StokesImageUtil::changeLabelsStokesToCorrStokes(StokesCoordinate &stokesCoord,
1980 : StokesImageUtil::PolRep polRep, //Int npol,
1981 : Vector<Int>&whichStokes)
1982 : {
1983 0 : Int inputNPol = (stokesCoord.stokes()).nelements();
1984 0 : Vector<Int> svec = stokesCoord.stokes();
1985 0 : AlwaysAssert( (inputNPol==1 || inputNPol==2 || inputNPol==3 || inputNPol), AipsError );
1986 :
1987 0 : switch( inputNPol )
1988 : {
1989 0 : case 1:
1990 0 : whichStokes.resize(1);
1991 : // by default, set to what the input is. This will take care of RR,LL,RL,LR,XX,YY,XY,YX and I.
1992 0 : whichStokes[0]=svec[0];
1993 : // for Q,U,V, two correlations needs to be gridded
1994 0 : if(polRep==StokesImageUtil::CIRCULAR && Stokes::type(svec[0])==Stokes::Q)
1995 0 : {whichStokes.resize(2); whichStokes[0]=Stokes::RL; whichStokes[1]=Stokes::LR; }
1996 0 : else if(polRep==StokesImageUtil::CIRCULAR && Stokes::type(svec[0])==Stokes::U)
1997 0 : {whichStokes.resize(2); whichStokes[0]=Stokes::RL; whichStokes[1]=Stokes::LR; }
1998 0 : else if(polRep==StokesImageUtil::CIRCULAR && Stokes::type(svec[0])==Stokes::V)
1999 0 : {whichStokes.resize(2); whichStokes[0]=Stokes::RR; whichStokes[1]=Stokes::LL; }
2000 0 : else if(polRep==StokesImageUtil::LINEAR && Stokes::type(svec[0])==Stokes::Q)
2001 0 : {whichStokes.resize(2); whichStokes[0]=Stokes::XX; whichStokes[1]=Stokes::YY; }
2002 0 : else if(polRep==StokesImageUtil::LINEAR && Stokes::type(svec[0])==Stokes::U)
2003 0 : {whichStokes.resize(2); whichStokes[0]=Stokes::XY; whichStokes[1]=Stokes::YX; }
2004 0 : else if(polRep==StokesImageUtil::LINEAR && Stokes::type(svec[0])==Stokes::V)
2005 0 : {whichStokes.resize(2); whichStokes[0]=Stokes::XY; whichStokes[1]=Stokes::YX; }
2006 0 : break;
2007 0 : case 2:
2008 0 : whichStokes.resize(2);
2009 : // by default, set to what the input is. This will take care of RRLL, RLLR, XXYY, XYYX
2010 0 : whichStokes(0)=svec[0];
2011 0 : whichStokes(1)=svec[1];
2012 : // only 2 correlations need to be gridded
2013 0 : if(polRep==StokesImageUtil::CIRCULAR && Stokes::type(svec[0])==Stokes::I && Stokes::type(svec[1])==Stokes::V)
2014 0 : {whichStokes(0)=Stokes::RR; whichStokes(1)=Stokes::LL;}
2015 0 : else if(polRep==StokesImageUtil::CIRCULAR && Stokes::type(svec[0])==Stokes::Q && Stokes::type(svec[1])==Stokes::U)
2016 0 : {whichStokes(0)=Stokes::RL; whichStokes(1)=Stokes::LR;}
2017 0 : else if(polRep==StokesImageUtil::LINEAR && Stokes::type(svec[0])==Stokes::I && Stokes::type(svec[1])==Stokes::Q)
2018 0 : {whichStokes(0)=Stokes::XX; whichStokes(1)=Stokes::YY;}
2019 0 : else if(polRep==StokesImageUtil::LINEAR && Stokes::type(svec[0])==Stokes::U && Stokes::type(svec[1])==Stokes::V)
2020 0 : {whichStokes(0)=Stokes::XY; whichStokes(1)=Stokes::YX;}
2021 : // all 4 correlations to be gridded. Only difference with above is CIRC to LIN
2022 0 : else if( (polRep==StokesImageUtil::LINEAR && Stokes::type(svec[0])==Stokes::I && Stokes::type(svec[1])==Stokes::V) ||
2023 0 : (polRep==StokesImageUtil::LINEAR && Stokes::type(svec[0])==Stokes::Q && Stokes::type(svec[1])==Stokes::U) )
2024 : {
2025 0 : whichStokes.resize(4);
2026 0 : whichStokes(0)=Stokes::XX; whichStokes(1)=Stokes::XY;
2027 0 : whichStokes(2)=Stokes::YX; whichStokes(3)=Stokes::YY;
2028 : }
2029 0 : else if( (polRep==StokesImageUtil::CIRCULAR && Stokes::type(svec[0])==Stokes::I && Stokes::type(svec[1])==Stokes::Q) ||
2030 0 : (polRep==StokesImageUtil::CIRCULAR && Stokes::type(svec[0])==Stokes::U && Stokes::type(svec[1])==Stokes::V) )
2031 : {
2032 0 : whichStokes.resize(4);
2033 0 : whichStokes(0)=Stokes::RR; whichStokes(1)=Stokes::RL;
2034 0 : whichStokes(2)=Stokes::LR; whichStokes(3)=Stokes::LL;
2035 : }
2036 0 : break;
2037 0 : case 3: /* If npol=3, all 4 correlations need to be gridded */
2038 : case 4: /* Select all 4 correlations when npol=4 */
2039 0 : whichStokes.resize(4);
2040 0 : if( polRep==StokesImageUtil::LINEAR)
2041 : {
2042 0 : whichStokes(0)=Stokes::XX;
2043 0 : whichStokes(1)=Stokes::XY;
2044 0 : whichStokes(2)=Stokes::YX;
2045 0 : whichStokes(3)=Stokes::YY;
2046 : }
2047 : else
2048 : {
2049 0 : whichStokes(0)=Stokes::RR;
2050 0 : whichStokes(1)=Stokes::RL;
2051 0 : whichStokes(2)=Stokes::LR;
2052 0 : whichStokes(3)=Stokes::LL;
2053 : }
2054 0 : break;
2055 : }
2056 :
2057 : // Verify that all entries in whichStokes are present in the data
2058 : // This is to catch things like : dataset contains only RR,LL, but the user has asked for IQUV.
2059 :
2060 :
2061 0 : }// end of changeStokesToCorrStokes
2062 :
2063 :
2064 : /* This function is not called from anywhere !!!! It should go. */
2065 : #if 0
2066 : CoordinateSystem
2067 : StokesImageUtil::CStokesCoordFromImage(const ImageInterface<Complex>& image,
2068 : Vector<Int>& whichStokes,
2069 : StokesImageUtil::PolRep polRep) {
2070 :
2071 : IPosition shape=image.shape();
2072 :
2073 : Int npol=shape(2);
2074 :
2075 : CoordinateSystem coord=image.coordinates();
2076 :
2077 : Int directionIndex=coord.findCoordinate(Coordinate::DIRECTION);
2078 : DirectionCoordinate directionCoord=coord.directionCoordinate(directionIndex);
2079 :
2080 : Int spectralIndex=coord.findCoordinate(Coordinate::SPECTRAL);
2081 : SpectralCoordinate spectralCoord=coord.spectralCoordinate(spectralIndex);
2082 :
2083 : // Polarization: If the specified whichStokes are ok, we use them
2084 : // otherwise we guess
2085 : if(Int(whichStokes.nelements())!=npol) {
2086 : whichStokes.resize(npol);
2087 : // Polarization
2088 : if (polRep==StokesImageUtil::LINEAR) {
2089 : switch(npol) {
2090 : case 1:
2091 : whichStokes.resize(1);
2092 : whichStokes(1)=Stokes::I;
2093 : break;
2094 : case 2:
2095 : whichStokes.resize(2);
2096 : whichStokes(1)=Stokes::XX;
2097 : whichStokes(0)=Stokes::YY;
2098 : break;
2099 : default:
2100 : whichStokes.resize(4);
2101 : whichStokes(0)=Stokes::XX;
2102 : whichStokes(1)=Stokes::XY;
2103 : whichStokes(2)=Stokes::YX;
2104 : whichStokes(3)=Stokes::YY;
2105 : }
2106 : }
2107 : else {
2108 : switch(npol) {
2109 : case 1:
2110 : whichStokes.resize(1);
2111 : whichStokes(0)=Stokes::I;
2112 : break;
2113 : case 2:
2114 : whichStokes.resize(2);
2115 : whichStokes(0)=Stokes::LL;
2116 : whichStokes(1)=Stokes::RR;
2117 : break;
2118 : default:
2119 : whichStokes.resize(4);
2120 : whichStokes(0)=Stokes::LL;
2121 : whichStokes(1)=Stokes::LR;
2122 : whichStokes(2)=Stokes::RL;
2123 : whichStokes(3)=Stokes::RR;
2124 : };
2125 : }
2126 : }
2127 : StokesCoordinate stokesCoord(whichStokes);
2128 :
2129 : // Now set up coordinates for image.
2130 : CoordinateSystem coordInfo;
2131 : coordInfo.addCoordinate(directionCoord);
2132 : coordInfo.addCoordinate(stokesCoord);
2133 : coordInfo.addCoordinate(spectralCoord);
2134 : return coordInfo;
2135 :
2136 : }
2137 : #endif
2138 :
2139 : // Return a map to RA, DEC, pol, chan. 0 is RA, 1 is Dec, 2 is
2140 : // polarization, and 3 is Channel
2141 0 : Bool StokesImageUtil::StokesMap(Vector<Int>& map, const CoordinateSystem& coord) {
2142 :
2143 0 : map.resize(4);
2144 0 : map=-1;
2145 :
2146 0 : Int dirIndex=coord.findCoordinate(Coordinate::DIRECTION);
2147 0 : if(dirIndex>-1) {
2148 0 : Vector<Int> dirAxes=coord.pixelAxes(dirIndex);
2149 0 : if(dirAxes.nelements()>2) {
2150 0 : return false;
2151 : }
2152 0 : map(0)=dirAxes(0);
2153 0 : map(1)=dirAxes(1);
2154 : }
2155 : else {
2156 0 : return false;
2157 : }
2158 :
2159 0 : Int stokesIndex=coord.findCoordinate(Coordinate::STOKES);
2160 0 : if(stokesIndex>-1) {
2161 0 : Vector<Int> stokesAxes=coord.pixelAxes(stokesIndex);
2162 0 : if(stokesAxes.nelements()>1) {
2163 0 : return false;
2164 : }
2165 0 : map(2)=stokesAxes(0);
2166 : }
2167 : else {
2168 0 : return false;
2169 : }
2170 :
2171 0 : Int spectralIndex=coord.findCoordinate(Coordinate::SPECTRAL);
2172 0 : if(spectralIndex>-1) {
2173 0 : Vector<Int> spectralAxes=coord.pixelAxes(spectralIndex);
2174 0 : if(spectralAxes.nelements()>1) {
2175 0 : return false;
2176 : }
2177 0 : map(3)=spectralAxes(0);
2178 : }
2179 : else {
2180 0 : return false;
2181 : }
2182 :
2183 0 : return true;
2184 : }
2185 :
2186 0 : void StokesImageUtil::BoxMask(ImageInterface<Float>& mask,
2187 : const IPosition& blc,
2188 : const IPosition& trc, const Float value)
2189 : {
2190 0 : LatticeStepper ls(mask.shape(), IPosition(4, mask.shape()(0), 1, 1, 1),
2191 0 : IPosition(4, 0, 1, 2, 3));
2192 0 : ls.subSection(blc, trc);
2193 0 : LatticeIterator<Float> mli(mask, ls);
2194 :
2195 : // Loop over all planes
2196 0 : for (mli.reset();!mli.atEnd();mli++) {
2197 0 : mli.rwCursor()=value;
2198 : }
2199 :
2200 0 : }
2201 :
2202 : // Change the representation used. The contents of the image
2203 : // are not changed!
2204 0 : void StokesImageUtil::changeCStokesRep(ImageInterface<Complex>& image,
2205 : StokesImageUtil::PolRep polRep) {
2206 :
2207 0 : CoordinateSystem coords=image.coordinates();
2208 :
2209 0 : Int stokesIndex=coords.findCoordinate(Coordinate::STOKES);
2210 : StokesCoordinate
2211 0 : stokesCoord=coords.stokesCoordinate(stokesIndex);
2212 :
2213 : ///// Int npol=stokesCoord.stokes().nelements(); // apparently not used and no side effects
2214 :
2215 : /* STOKESDBG */ //cout << "Util::changeCStokesRep - input - stokescoord : " << stokesCoord.stokes() << " npol : " << npol << endl;
2216 :
2217 0 : Vector<Int> whichStokes(0);
2218 : //whichStokes=0;
2219 0 : changeLabelsStokesToCorrStokes(stokesCoord, polRep, whichStokes);
2220 :
2221 0 : StokesCoordinate newStokesCoord(whichStokes);
2222 0 : coords.replaceCoordinate(newStokesCoord, stokesIndex);
2223 0 : image.setCoordinateInfo(coords);
2224 : /* STOKESDBG */ //cout << "Util::changeCStokesRep - output - stokescoord : " << newStokesCoord.stokes() << endl;
2225 0 : }
2226 :
2227 0 : Bool StokesImageUtil::
2228 : standardImageCoordinates(const ImageInterface<Complex>& image) {
2229 0 : return (standardImageCoordinates(image.coordinates()));
2230 : };
2231 :
2232 0 : Bool StokesImageUtil::
2233 : standardImageCoordinates(const ImageInterface<Float>& image) {
2234 0 : return (standardImageCoordinates(image.coordinates()));
2235 : };
2236 :
2237 0 : Bool StokesImageUtil::
2238 : standardImageCoordinates(const CoordinateSystem& coords) {
2239 0 : Bool isStandard = true;
2240 : {
2241 0 : Int ind=coords.findCoordinate(Coordinate::DIRECTION);
2242 0 : if (ind != 0) isStandard = false;
2243 0 : ind=coords.findCoordinate(Coordinate::STOKES);
2244 0 : if (ind != 1) isStandard = false;
2245 0 : ind=coords.findCoordinate(Coordinate::SPECTRAL);
2246 0 : if (ind != 2) isStandard = false;
2247 : }
2248 0 : return isStandard;
2249 : };
2250 :
2251 : } //#End casa namespace
2252 :
2253 :
|