Line data Source code
1 : //# Feather.cc: Implementation of Feather.h
2 : //# Copyright (C) 1997-2013
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 : //# $kgolap$
27 : #include <cmath>
28 : #include <synthesis/MeasurementEquations/Feather.h>
29 : #include <synthesis/MeasurementEquations/Imager.h>
30 : #include <synthesis/TransformMachines/StokesImageUtil.h>
31 : #include <casacore/casa/OS/HostInfo.h>
32 :
33 : #include <casacore/casa/Arrays/Matrix.h>
34 : #include <casacore/casa/Arrays/ArrayMath.h>
35 : #include <casacore/casa/Arrays/ArrayLogical.h>
36 : #include <casacore/casa/Arrays/IPosition.h>
37 : #include <iostream>
38 : #include <casacore/casa/Logging.h>
39 : #include <casacore/casa/Logging/LogIO.h>
40 : #include <casacore/casa/Logging/LogMessage.h>
41 : #include <casacore/casa/Logging/LogSink.h>
42 : #include <casacore/scimath/Mathematics/MathFunc.h>
43 : #include <casacore/tables/TaQL/ExprNode.h>
44 : #include <casacore/casa/Utilities/Assert.h>
45 : #include <casacore/casa/Arrays/ArrayMath.h>
46 : #include <casacore/casa/Arrays/Slice.h>
47 : #include <casacore/images/Images/TempImage.h>
48 : #include <casacore/images/Images/ImageInterface.h>
49 : #include <casacore/images/Images/PagedImage.h>
50 : #include <casacore/images/Images/ImageRegrid.h>
51 : #include <casacore/images/Images/ImageUtilities.h>
52 : #include <synthesis/TransformMachines/PBMath.h>
53 : #include <casacore/lattices/LEL/LatticeExpr.h>
54 : #include <casacore/lattices/LatticeMath/LatticeFFT.h>
55 : #include <casacore/coordinates/Coordinates/CoordinateSystem.h>
56 : #include <casacore/coordinates/Coordinates/DirectionCoordinate.h>
57 : #include <casacore/coordinates/Coordinates/SpectralCoordinate.h>
58 : #include <casacore/coordinates/Coordinates/StokesCoordinate.h>
59 : #include <casacore/coordinates/Coordinates/CoordinateUtil.h>
60 : #include <casacore/coordinates/Coordinates/Projection.h>
61 : #include <casacore/coordinates/Coordinates/ObsInfo.h>
62 :
63 : #include <components/ComponentModels/GaussianDeconvolver.h>
64 :
65 : using namespace casacore;
66 : namespace casa { //# NAMESPACE CASA - BEGIN
67 :
68 :
69 0 : Feather::Feather(): dishDiam_p(-1.0), cweightCalced_p(false), cweightApplied_p(false), sdScale_p(1.0){
70 0 : highIm_p=NULL;
71 0 : lowIm_p=NULL;
72 0 : lowImOrig_p=NULL;
73 0 : cwImage_p=NULL;
74 0 : cwHighIm_p=NULL;
75 0 : }
76 0 : Feather::Feather(const ImageInterface<Float>& SDImage, const ImageInterface<Float>& INTImage, Float sdscale) : dishDiam_p(-1.0), cweightCalced_p(false), cweightApplied_p(false), sdScale_p(sdscale){
77 :
78 0 : setINTImage(INTImage);
79 0 : lowImOrig_p=NULL;
80 0 : setSDImage(SDImage);
81 :
82 0 : cwImage_p=NULL;
83 0 : cwHighIm_p=NULL;
84 :
85 0 : }
86 0 : Feather::~Feather(){
87 0 : highIm_p=NULL;
88 0 : lowIm_p=NULL;
89 0 : cwImage_p=NULL;
90 0 : }
91 :
92 0 : void Feather::setSDImage(const ImageInterface<Float>& SDImage){
93 0 : LogIO os(LogOrigin("Feather", "setSDImage()", WHERE));
94 0 : if(highIm_p.null())
95 0 : throw(AipsError("High res image has to be defined before SD image"));
96 0 : ImageInfo lowInfo=SDImage.imageInfo();
97 0 : lBeam_p=lowInfo.restoringBeam();
98 0 : if(lBeam_p.isNull())
99 0 : throw(AipsError("No Single dish restoring beam info in image"));
100 0 : CoordinateSystem csyslow=SDImage.coordinates();
101 0 : CountedPtr<ImageInterface<Float> > sdcopy;
102 0 : sdcopy=new TempImage<Float>(SDImage.shape(), csyslow);
103 0 : (*sdcopy).copyData(SDImage);
104 0 : ImageUtilities::copyMiscellaneous(*sdcopy, SDImage);
105 0 : if(SDImage.getDefaultMask() != "")
106 0 : Imager::copyMask(*sdcopy, SDImage, SDImage.getDefaultMask());
107 0 : std::unique_ptr<ImageInterface<Float> > copyPtr;
108 0 : std::unique_ptr<ImageInterface<Float> > copyPtr2;
109 :
110 :
111 0 : Vector<Stokes::StokesTypes> stokesvec;
112 0 : if(CoordinateUtil::findStokesAxis(stokesvec, csyslow) <0){
113 0 : CoordinateUtil::addIAxis(csyslow);
114 :
115 0 : ImageUtilities::addDegenerateAxes (os, copyPtr, *sdcopy, "",
116 : false, false,"I", false, false,
117 : true);
118 0 : sdcopy=CountedPtr<ImageInterface<Float> >(copyPtr.get(), false);
119 :
120 : }
121 0 : if(CoordinateUtil::findSpectralAxis(csyslow) <0){
122 0 : CoordinateUtil::addFreqAxis(csyslow);
123 0 : ImageUtilities::addDegenerateAxes (os, copyPtr2, *sdcopy, "",
124 : false, true,
125 : "", false, false,
126 : true);
127 0 : sdcopy=CountedPtr<ImageInterface<Float> >(copyPtr2.get(), false);
128 : }
129 0 : lowIm_p=new TempImage<Float>(highIm_p->shape(), csysHigh_p);
130 : // regrid the single dish image
131 : {
132 0 : Vector<Int> dirAxes=CoordinateUtil::findDirectionAxes(csysHigh_p);
133 0 : IPosition axes(3,dirAxes(0),dirAxes(1),2);
134 0 : Int spectralAxisIndex=CoordinateUtil::findSpectralAxis(csysHigh_p);
135 0 : axes(2)=spectralAxisIndex;
136 0 : if(sdcopy->getDefaultMask() != "")
137 0 : lowIm_p->makeMask(sdcopy->getDefaultMask(), true, true, true, true);
138 :
139 0 : ImageRegrid<Float> ir;
140 0 : ir.regrid(*lowIm_p, Interpolate2D::LINEAR, axes, *sdcopy);
141 : }
142 : /*if(sdcopy->getDefaultMask() != ""){
143 : //Imager::copyMask(*lowIm_p, *sdcopy, sdcopy->getDefaultMask());
144 : lowIm_p->makeMask(sdcopy->getDefaultMask(), true, true);
145 : ImageUtilities::copyMask(*lowIm_p, *sdcopy,sdcopy->getDefaultMask() , sdcopy->getDefaultMask(), AxesSpecifier());
146 : lowIm_p->setDefaultMask(sdcopy->getDefaultMask());
147 :
148 : }
149 : */
150 :
151 0 : if(lowImOrig_p.null()){
152 0 : lowImOrig_p=new TempImage<Float>(lowIm_p->shape(), lowIm_p->coordinates(),0);
153 0 : lowImOrig_p->copyData(*lowIm_p);
154 0 : lBeamOrig_p=lBeam_p;
155 : }
156 0 : cweightCalced_p=false;
157 0 : }
158 :
159 0 : void Feather::convolveINT(const GaussianBeam& newHighBeam){
160 0 : GaussianBeam toBeUsed(Quantity(0.0, "arcsec"),Quantity(0.0, "arcsec"), Quantity(0.0, "deg")) ;
161 0 : Bool retval=true;
162 : try {
163 : //cerr << "highBeam " << hBeam_p.getMajor() << " " << hBeam_p.getMinor() << " " << hBeam_p.getPA() << endl;
164 : retval=
165 0 : GaussianDeconvolver::deconvolve(toBeUsed, newHighBeam, hBeam_p);
166 : //cerr << "beam to be used " << toBeUsed.getMajor() << " " << toBeUsed.getMinor() << " " << toBeUsed.getPA() << endl;
167 : }
168 0 : catch (const AipsError& x) {
169 0 : if(toBeUsed.getMajor("arcsec")==0.0)
170 0 : throw(AipsError("new Beam may be smaller than the beam of original Interferometer image"));
171 : }
172 : try{
173 0 : StokesImageUtil::Convolve(*highIm_p, toBeUsed, true);
174 : }
175 0 : catch(const AipsError& x){
176 0 : throw(AipsError("Could not convolve INT image for some reason; try a lower resolution may be"));
177 : }
178 0 : hBeam_p=newHighBeam;
179 :
180 : //need to redo feather application
181 0 : cweightApplied_p=false;
182 : (void)retval; // avoid compiler warning
183 0 : }
184 :
185 0 : void Feather::setINTImage(const ImageInterface<Float>& INTImage){
186 0 : LogIO os(LogOrigin("Feather", "setINTImage()", WHERE));
187 0 : ImageInfo highInfo=INTImage.imageInfo();
188 0 : hBeam_p=highInfo.restoringBeam();
189 0 : if(hBeam_p.isNull())
190 0 : throw(AipsError("No high-resolution restoring beam info in image"));
191 0 : csysHigh_p=INTImage.coordinates();
192 0 : CountedPtr<ImageInterface<Float> > intcopy=new TempImage<Float>(INTImage.shape(), csysHigh_p);
193 0 : (*intcopy).copyData(INTImage);
194 0 : ImageUtilities::copyMiscellaneous(*intcopy, INTImage);
195 0 : if(INTImage.getDefaultMask() != "")
196 0 : Imager::copyMask(*intcopy, INTImage, INTImage.getDefaultMask());
197 0 : std::unique_ptr<ImageInterface<Float> > copyPtr;
198 0 : std::unique_ptr<ImageInterface<Float> > copyPtr2;
199 :
200 :
201 0 : Vector<Stokes::StokesTypes> stokesvec;
202 0 : if(CoordinateUtil::findStokesAxis(stokesvec, csysHigh_p) <0){
203 0 : CoordinateUtil::addIAxis(csysHigh_p);
204 0 : ImageUtilities::addDegenerateAxes (os, copyPtr, *intcopy, "",
205 : false, false,"I", false, false,
206 : true);
207 0 : intcopy=CountedPtr<ImageInterface<Float> >(copyPtr.get(), false);
208 :
209 : }
210 0 : if(CoordinateUtil::findSpectralAxis(csysHigh_p) <0){
211 0 : CoordinateUtil::addFreqAxis(csysHigh_p);
212 0 : ImageUtilities::addDegenerateAxes (os, copyPtr2, *intcopy, "",
213 : false, true,
214 : "", false, false,
215 : true);
216 0 : intcopy=CountedPtr<ImageInterface<Float> >(copyPtr2.get(), false);
217 : }
218 :
219 :
220 0 : highIm_p=new TempImage<Float>(intcopy->shape(), csysHigh_p);
221 :
222 0 : highIm_p->copyData(*intcopy);
223 0 : ImageUtilities::copyMiscellaneous(*highIm_p, *intcopy);
224 0 : String maskname=intcopy->getDefaultMask();
225 0 : if(maskname != ""){
226 0 : Imager::copyMask(*highIm_p, *intcopy, maskname);
227 :
228 : }
229 0 : cweightCalced_p=false;
230 :
231 0 : }
232 :
233 0 : Bool Feather::setEffectiveDishDiam(const Float xdiam, const Float ydiam){
234 0 : dishDiam_p=ydiam >0 ? min(xdiam, ydiam) : xdiam;
235 : {//reset to the original SD image
236 0 : lowIm_p->copyData(*lowImOrig_p);
237 0 : lBeam_p=lBeamOrig_p;
238 : }
239 : //Change the beam of SD image
240 0 : Double freq = worldFreq(lowIm_p->coordinates(), 0);
241 : //cerr << "Freq " << freq << endl;
242 0 : Quantity halfpb=Quantity(1.22*C::c/freq/dishDiam_p, "rad");
243 0 : GaussianBeam newBeam(halfpb, halfpb, Quantity(0.0, "deg"));
244 0 : GaussianBeam toBeUsed;
245 : try {
246 0 : GaussianDeconvolver::deconvolve(toBeUsed, newBeam, lBeam_p);
247 : }
248 0 : catch (const AipsError& x) {
249 0 : throw(AipsError("Beam due to new effective diameter may be smaller than the beam of original dish image"));
250 : }
251 : try{
252 : //cerr <<"To be used " << toBeUsed.getMajor() << " " << toBeUsed.getMinor() <<
253 : //" " << toBeUsed.getPA() << endl;
254 0 : StokesImageUtil::Convolve(*lowIm_p, toBeUsed, true);
255 : }
256 0 : catch(const AipsError& x){
257 0 : throw(AipsError("Could not convolve SD image for some reason; try a smaller effective diameter may be"));
258 : }
259 0 : lBeam_p=newBeam;
260 : //reset cweight if it was calculated already
261 0 : cweightCalced_p=false;
262 0 : cweightApplied_p=false;
263 :
264 0 : return true;
265 : }
266 0 : void Feather::getEffectiveDishDiam(Float& xdiam, Float& ydiam){
267 0 : if(dishDiam_p <0){
268 0 : if(lBeam_p.isNull())
269 0 : throw(AipsError("No Single dish restoring beam info in image"));
270 0 : Double maj=lBeam_p.getMajor("rad");
271 0 : Double freq = worldFreq(csysHigh_p, 0);
272 : //cerr << "Freq " << freq << endl;
273 0 : dishDiam_p=1.22*C::c/freq/maj;
274 : }
275 0 : xdiam=dishDiam_p;
276 0 : ydiam=dishDiam_p;
277 0 : }
278 0 : void Feather::setSDScale(Float sdscale){
279 0 : sdScale_p=sdscale;
280 0 : }
281 :
282 0 : void Feather::getFTCutSDImage(Vector<Float>& ux, Vector<Float>& xamp, Vector<Float>& uy, Vector<Float>& yamp, const Bool radial){
283 0 : if(radial){
284 0 : uy.resize();
285 0 : yamp.resize();
286 0 : return getRadialCut(ux, xamp, *lowIm_p);
287 : }
288 :
289 0 : TempImage<Complex> cimagelow(lowIm_p->shape(), lowIm_p->coordinates() );
290 0 : StokesImageUtil::From(cimagelow, *lowIm_p);
291 0 : LatticeFFT::cfft2d( cimagelow );
292 0 : getCutXY(ux, xamp, uy, yamp, cimagelow);
293 :
294 : }
295 0 : void Feather::getFTCutIntImage(Vector<Float>& ux, Vector<Float>& xamp, Vector<Float>& uy, Vector<Float>& yamp, const Bool radial){
296 0 : if(radial){
297 0 : uy.resize();
298 0 : yamp.resize();
299 0 : return getRadialCut(ux, xamp, *highIm_p);
300 : }
301 0 : TempImage<Complex> cimagehigh(highIm_p->shape(), highIm_p->coordinates() );
302 0 : StokesImageUtil::From(cimagehigh, *highIm_p);
303 0 : LatticeFFT::cfft2d( cimagehigh );
304 0 : getCutXY(ux, xamp, uy, yamp, cimagehigh);
305 :
306 : }
307 0 : void Feather::getFeatherINT(Vector<Float>& ux, Vector<Float>& xamp, Vector<Float>& uy, Vector<Float>& yamp, Bool radial){
308 :
309 0 : calcCWeightImage();
310 0 : if(radial){
311 0 : uy.resize();
312 0 : yamp.resize();
313 0 : getRadialCut(xamp, *cwImage_p);
314 0 : getRadialUVval(xamp.shape()[0], cwImage_p->shape(), cwImage_p->coordinates(), ux);
315 :
316 :
317 : }
318 : else{
319 0 : getCutXY(ux, xamp, uy, yamp, *cwImage_p);
320 : }
321 0 : }
322 0 : void Feather::getFeatherSD(Vector<Float>& ux, Vector<Float>& xamp, Vector<Float>& uy, Vector<Float>& yamp, Bool radial, Bool normalize){
323 0 : calcCWeightImage();
324 0 : Vector<Float> xampInt, yampInt;
325 0 : if(radial){
326 0 : uy.resize();
327 0 : yamp.resize();
328 0 : getRadialCut(xampInt, *cwImage_p);
329 0 : getRadialUVval(xampInt.shape()[0], cwImage_p->shape(), cwImage_p->coordinates(), ux);
330 :
331 : }
332 : else{
333 0 : getCutXY(ux, xampInt, uy, yampInt, *cwImage_p);
334 0 : yamp.resize();
335 0 : yamp=(Float(1.0) - yampInt);
336 0 : if(!normalize)
337 0 : yamp=yamp*Float(sdScale_p*hBeam_p.getArea("arcsec2")/lBeam_p.getArea("arcsec2"));
338 : }
339 :
340 0 : xamp.resize();
341 0 : xamp=(Float(1.0) - xampInt);
342 0 : if(!normalize)
343 0 : xamp=xamp*Float(sdScale_p*hBeam_p.getArea("arcsec2")/lBeam_p.getArea("arcsec2"));
344 :
345 :
346 0 : }
347 0 : void Feather::getFeatheredCutSD(Vector<Float>& ux, Vector<Float>& xamp, Vector<Float>& uy, Vector<Float>& yamp, Bool radial){
348 :
349 0 : getFTCutSDImage(ux, xamp, uy,yamp, radial);
350 0 : xamp *=Float(sdScale_p*hBeam_p.getArea("arcsec2")/lBeam_p.getArea("arcsec2"));
351 :
352 0 : if(yamp.nelements() >0)
353 0 : yamp *=Float(sdScale_p*hBeam_p.getArea("arcsec2")/lBeam_p.getArea("arcsec2"));
354 0 : }
355 :
356 0 : void Feather::getFeatheredCutINT(Vector<Float>& ux, Vector<Float>& xamp, Vector<Float>& uy, Vector<Float>& yamp, Bool radial){
357 0 : applyFeather();
358 0 : if(radial){
359 0 : uy.resize();
360 0 : yamp.resize();
361 0 : getRadialCut(xamp, *cwHighIm_p);
362 0 : getRadialUVval(xamp.shape()[0], cwHighIm_p->shape(), cwHighIm_p->coordinates(), ux);
363 : }
364 : else
365 0 : getCutXY(ux, xamp, uy, yamp, *cwHighIm_p);
366 0 : }
367 :
368 0 : void Feather::clearWeightFlags(){
369 0 : cweightCalced_p=false;
370 0 : cweightApplied_p = false;
371 0 : }
372 :
373 0 : void Feather::applyFeather(){
374 0 : if(cweightApplied_p)
375 0 : return;
376 0 : calcCWeightImage();
377 0 : if(highIm_p.null())
378 0 : throw(AipsError("No high resolution image set"));
379 0 : cwHighIm_p=new TempImage<Complex>(highIm_p->shape(), highIm_p->coordinates() );
380 0 : StokesImageUtil::From(*cwHighIm_p, *highIm_p);
381 0 : LatticeFFT::cfft2d( *cwHighIm_p );
382 0 : Vector<Int> extraAxes(cwHighIm_p->shape().nelements()-2);
383 0 : if(extraAxes.nelements() > 0){
384 :
385 0 : if(extraAxes.nelements() ==2){
386 0 : Int n3=cwHighIm_p->shape()(2);
387 0 : Int n4=cwHighIm_p->shape()(3);
388 0 : IPosition blc(cwHighIm_p->shape());
389 0 : IPosition trc(cwHighIm_p->shape());
390 0 : blc(0)=0; blc(1)=0;
391 0 : trc(0)=cwHighIm_p->shape()(0)-1;
392 0 : trc(1)=cwHighIm_p->shape()(1)-1;
393 0 : for (Int j=0; j < n3; ++j){
394 0 : for (Int k=0; k < n4 ; ++k){
395 0 : blc(2)=j; trc(2)=j;
396 0 : blc(3)=k; trc(3)=k;
397 0 : Slicer sl(blc, trc, Slicer::endIsLast);
398 0 : SubImage<Complex> cimagehighSub(*cwHighIm_p, sl, true);
399 0 : cimagehighSub.copyData( (LatticeExpr<Complex>)((cimagehighSub * (*cwImage_p))));
400 : }
401 : }
402 : }
403 : }
404 : else{
405 0 : cwHighIm_p->copyData(
406 0 : (LatticeExpr<Complex>)(((*cwHighIm_p) * (*cwImage_p) )));
407 : }
408 0 : cweightApplied_p=true;
409 :
410 : }
411 :
412 0 : void Feather::calcCWeightImage(){
413 0 : if(cweightCalced_p)
414 0 : return;
415 0 : if(highIm_p.null())
416 0 : throw(AipsError("No Interferometer image was defined"));
417 0 : IPosition myshap(highIm_p->shape());
418 0 : Vector<Int> dirAxes;
419 0 : dirAxes=CoordinateUtil::findDirectionAxes(highIm_p->coordinates());
420 0 : for( uInt k=0; k< myshap.nelements(); ++k){
421 0 : if( (Int(k) != dirAxes[0]) && (Int(k) != dirAxes[1]))
422 0 : myshap(k)=1;
423 : }
424 :
425 0 : cwImage_p=new TempImage<Complex>(myshap, highIm_p->coordinates());
426 : {
427 0 : TempImage<Float> lowpsf(myshap, cwImage_p->coordinates());
428 0 : lowpsf.set(0.0);
429 0 : IPosition center(4, Int((myshap(0)/4)*2),
430 0 : Int((myshap(1)/4)*2),0,0);
431 0 : lowpsf.putAt(1.0, center);
432 0 : StokesImageUtil::Convolve(lowpsf, lBeam_p, false);
433 0 : StokesImageUtil::From(*cwImage_p, lowpsf);
434 : }
435 0 : LatticeFFT::cfft2d( *cwImage_p );
436 0 : LatticeExprNode node = max( *cwImage_p );
437 0 : Float fmax = abs(node.getComplex());
438 0 : cwImage_p->copyData( (LatticeExpr<Complex>)( 1.0f - (*cwImage_p)/fmax ) );
439 0 : cweightCalced_p=true;
440 0 : cweightApplied_p=false;
441 : }
442 :
443 0 : void Feather::getCutXY(Vector<Float>& ux, Vector<Float>& xamp,
444 : Vector<Float>& uy, Vector<Float>& yamp,
445 : const ImageInterface<Float>& image){
446 :
447 :
448 0 : TempImage<Complex> cimage(image.shape(), image.coordinates() );
449 0 : StokesImageUtil::From(cimage, image);
450 0 : if(image.getDefaultMask()!=""){
451 0 : ImageRegion elMask=image.getRegion(image.getDefaultMask(),
452 0 : RegionHandler::Masks);
453 0 : LatticeRegion latReg=elMask.toLatticeRegion(image.coordinates(), image.shape());
454 0 : ArrayLattice<Bool> pixmask(latReg.get());
455 0 : LatticeExpr<Complex> myexpr(iif(pixmask, cimage, Complex(0.0)) );
456 0 : cimage.copyData(myexpr);
457 :
458 : }
459 :
460 0 : LatticeFFT::cfft2d( cimage );
461 0 : getCutXY(ux, xamp, uy, yamp, cimage);
462 :
463 :
464 0 : }
465 :
466 0 : void Feather::getRadialCut(Vector<Float>& radius, Vector<Float>& radialAmp,
467 : const ImageInterface<Float>& image){
468 :
469 0 : TempImage<Complex> cimage(image.shape(), image.coordinates() );
470 0 : StokesImageUtil::From(cimage, image);
471 0 : LatticeFFT::cfft2d( cimage );
472 0 : radialAmp.resize();
473 0 : getRadialCut(radialAmp, cimage);
474 :
475 0 : getRadialUVval(radialAmp.shape()[0], cimage.shape(), cimage.coordinates(), radius);
476 : ////Get the radial value in uv- units.
477 : /* Double freq=worldFreq(image.coordinates(), 0);
478 : Int dirCoordIndex=image.coordinates().findCoordinate(Coordinate::DIRECTION);
479 : DirectionCoordinate dc=image.coordinates().directionCoordinate(dirCoordIndex);
480 : Vector<Bool> axes(2); axes(0)=true;axes(1)=true;
481 : Vector<Int> elshape(2);
482 : Vector<Int> directionIndex=CoordinateUtil::findDirectionAxes(image.coordinates());
483 : elshape(0)=image.shape()[directionIndex(0)];
484 : elshape(1)=image.shape()[directionIndex(1)];
485 : Coordinate* ftdc=dc.makeFourierCoordinate(axes,elshape);
486 : Vector<Double> xpix(radialAmp.nelements());
487 : indgen(xpix);
488 : xpix +=Double(image.shape()[directionIndex(0)])/2.0;
489 : Matrix<Double> pix(2, xpix.nelements());
490 : Matrix<Double> world(2, xpix.nelements());
491 : Vector<Bool> failures;
492 : pix.row(1)=elshape(1)/2;
493 : pix.row(0)=xpix;
494 : ftdc->toWorldMany(world, pix, failures);
495 : xpix=world.row(0);
496 : xpix=fabs(xpix)*(C::c)/freq;
497 : radius.resize(xpix.nelements());
498 : convertArray(radius, xpix);
499 : */
500 :
501 0 : }
502 0 : void Feather::getRadialUVval(const Int npix, const IPosition& imshape, const CoordinateSystem& csys, Vector<Float>& radius){
503 :
504 : ////Get the radial value in uv- units.
505 0 : Double freq=worldFreq(csys, 0);
506 0 : Int dirCoordIndex=csys.findCoordinate(Coordinate::DIRECTION);
507 0 : DirectionCoordinate dc=csys.directionCoordinate(dirCoordIndex);
508 0 : Vector<Bool> axes(2); axes(0)=true;axes(1)=true;
509 0 : Vector<Int> elshape(2);
510 0 : Vector<Int> directionIndex=CoordinateUtil::findDirectionAxes(csys);
511 0 : elshape(0)=imshape[directionIndex(0)];
512 0 : elshape(1)=imshape[directionIndex(1)];
513 0 : Coordinate* ftdc=dc.makeFourierCoordinate(axes,elshape);
514 0 : Vector<Double> xpix(npix);
515 0 : indgen(xpix);
516 0 : xpix +=Double(imshape[directionIndex(0)])/2.0;
517 0 : Matrix<Double> pix(2, npix);
518 0 : Matrix<Double> world(2, npix);
519 0 : Vector<Bool> failures;
520 0 : pix.row(1)=elshape(1)/2;
521 0 : pix.row(0)=xpix;
522 0 : ftdc->toWorldMany(world, pix, failures);
523 0 : xpix=world.row(0);
524 0 : xpix=fabs(xpix)*(C::c)/freq;
525 0 : radius.resize(xpix.nelements());
526 0 : convertArray(radius, xpix);
527 :
528 0 : }
529 0 : void Feather::getRadialCut(Vector<Float>& radialAmp, ImageInterface<Complex>& ftimage) {
530 0 : CoordinateSystem ftCoords(ftimage.coordinates());
531 : //////////////////////
532 : /*{
533 : PagedImage<Float> thisScreen(ftimage.shape(), ftCoords, "FFTimage");
534 : LatticeExpr<Float> le(abs(ftimage));
535 : thisScreen.copyData(le);
536 : }*/
537 : /////////////////////
538 0 : Vector<Int> directionIndex=CoordinateUtil::findDirectionAxes(ftCoords);
539 0 : Int spectralIndex=CoordinateUtil::findSpectralAxis(ftCoords);
540 0 : IPosition start=ftimage.shape();
541 0 : IPosition shape=ftimage.shape();
542 0 : Int centreX=shape[directionIndex(0)]/2;
543 0 : Int centreY=shape[directionIndex(1)]/2;
544 0 : Int arrLen=min(centreX, centreY);
545 :
546 0 : radialAmp.resize(arrLen);
547 0 : radialAmp.set(0.0);
548 0 : Array<Complex> tmpval;
549 :
550 0 : for(uInt k=0; k < shape.nelements(); ++k){
551 0 : start[k]=0;
552 : ///value for a single pixel in x, y, and pol
553 0 : if((k != uInt(spectralIndex)))
554 0 : shape[k]=1;
555 : }
556 : Int counter;
557 : Float sumval;
558 0 : for (Int pix =0 ; pix < arrLen; ++pix){
559 0 : sumval=0;
560 0 : counter=0;
561 0 : for (Int xval=0; xval <= pix; ++xval){
562 0 : Int yval=std::lround(sqrt(Double(pix*pix-xval*xval)));
563 0 : start[directionIndex[0]]=xval+centreX;
564 0 : start[directionIndex[1]]=yval+centreY;
565 0 : tmpval.resize();
566 0 : ftimage.getSlice(tmpval, start, shape, true);
567 0 : sumval+=fabs(mean(tmpval));
568 0 : counter+=1;
569 : }
570 0 : radialAmp[pix]=sumval/float(counter);
571 : }
572 :
573 :
574 0 : }
575 :
576 0 : void Feather::getCutXY(Vector<Float>& ux, Vector<Float>& xamp,
577 : Vector<Float>& uy, Vector<Float>& yamp, ImageInterface<Complex>& ftimage){
578 :
579 0 : CoordinateSystem ftCoords(ftimage.coordinates());
580 0 : Double freq=worldFreq(ftCoords, 0);
581 : ////
582 0 : Vector<Int> directionIndex=CoordinateUtil::findDirectionAxes(ftCoords);
583 0 : Int spectralIndex=CoordinateUtil::findSpectralAxis(ftCoords);
584 0 : Array<Complex> tmpval;
585 0 : Vector<Complex> meanval;
586 0 : IPosition start=ftimage.shape();
587 0 : IPosition shape=ftimage.shape();
588 0 : shape[directionIndex(0)]=shape[directionIndex(0)]/2;
589 0 : shape[directionIndex(1)]=shape[directionIndex(1)]/2;
590 0 : for(uInt k=0; k < shape.nelements(); ++k){
591 0 : start[k]=0;
592 0 : if((k != uInt(directionIndex(1))) && (k != uInt(spectralIndex)))
593 0 : shape[k]=1;
594 : }
595 0 : start[directionIndex(1)]=ftimage.shape()[directionIndex(1)]/2;
596 0 : start[directionIndex(0)]=ftimage.shape()[directionIndex(0)]/2;
597 0 : ftimage.getSlice(tmpval, start, shape, true);
598 0 : if(shape[spectralIndex] >1){
599 0 : meanval.resize(shape[directionIndex(1)]);
600 0 : Matrix<Complex> retmpval(tmpval);
601 0 : Bool colOrRow=spectralIndex > directionIndex(1);
602 0 : for (uInt k=0; k < meanval.nelements(); ++k){
603 0 : meanval[k]=colOrRow ? mean(retmpval.row(k)) : mean(retmpval.column(k));
604 : }
605 : }
606 : else{
607 0 : meanval=tmpval;
608 : }
609 0 : xamp.resize();
610 0 : xamp=amplitude(meanval);
611 0 : tmpval.resize();
612 0 : shape=ftimage.shape();
613 0 : shape[directionIndex(0)]=shape[directionIndex(0)]/2;
614 0 : shape[directionIndex(1)]=shape[directionIndex(1)]/2;
615 0 : for(uInt k=0; k < shape.nelements(); ++k){
616 0 : start[k]=0;
617 0 : if((k != uInt(directionIndex(0))) && (k != uInt(spectralIndex)))
618 0 : shape[k]=1;
619 : }
620 0 : start[directionIndex(1)]=ftimage.shape()[directionIndex(1)]/2;
621 0 : start[directionIndex(0)]=ftimage.shape()[directionIndex(0)]/2;
622 0 : ftimage.getSlice(tmpval, start, shape, true);
623 0 : if(shape[spectralIndex] >1){
624 0 : meanval.resize(shape[directionIndex(0)]);
625 0 : Bool colOrRow=spectralIndex > directionIndex(0);
626 0 : Matrix<Complex> retmpval(tmpval);
627 0 : for (uInt k=0; k < meanval.nelements(); ++k){
628 0 : meanval[k]=colOrRow ? mean(retmpval.row(k)) : mean(retmpval.column(k));
629 : }
630 : }
631 : else{
632 0 : meanval.resize( tmpval.size());
633 0 : meanval=tmpval;
634 : }
635 0 : yamp.resize();
636 0 : yamp=amplitude(meanval);
637 0 : Int dirCoordIndex=ftCoords.findCoordinate(Coordinate::DIRECTION);
638 0 : DirectionCoordinate dc=ftCoords.directionCoordinate(dirCoordIndex);
639 0 : Vector<Bool> axes(2); axes(0)=true;axes(1)=true;
640 0 : Vector<Int> elshape(2);
641 0 : elshape(0)=ftimage.shape()[directionIndex(0)];
642 0 : elshape(1)=ftimage.shape()[directionIndex(1)];
643 0 : Coordinate* ftdc=dc.makeFourierCoordinate(axes,elshape);
644 0 : Vector<Double> xpix(xamp.nelements());
645 0 : indgen(xpix);
646 0 : xpix +=Double(ftimage.shape()[directionIndex(0)])/2.0;
647 0 : Matrix<Double> pix(2, xpix.nelements());
648 0 : Matrix<Double> world(2, xpix.nelements());
649 0 : Vector<Bool> failures;
650 0 : pix.row(1)=elshape(0)/2;
651 0 : pix.row(0)=xpix;
652 0 : ftdc->toWorldMany(world, pix, failures);
653 0 : xpix=world.row(0);
654 : //cerr << "xpix " << xpix << endl;
655 0 : xpix=fabs(xpix)*(C::c)/freq;
656 0 : Vector<Double> ypix(yamp.nelements());
657 0 : indgen(ypix);
658 0 : ypix +=Double(ftimage.shape()[directionIndex(1)])/2.0;
659 0 : pix.resize(2, ypix.nelements());
660 0 : world.resize();
661 0 : pix.row(1)=ypix;
662 0 : pix.row(0)=elshape(1)/2;
663 0 : ftdc->toWorldMany(world, pix, failures);
664 0 : ypix=world.row(1);
665 0 : ypix=fabs(ypix)*(C::c/freq);
666 0 : ux.resize(xpix.nelements());
667 0 : uy.resize(ypix.nelements());
668 0 : convertArray(ux, xpix);
669 0 : convertArray(uy, ypix);
670 :
671 :
672 0 : }
673 :
674 :
675 :
676 0 : Bool Feather::saveFeatheredImage(const String& imagename){
677 0 : applyFeather();
678 : Int stokesAxis, spectralAxis;
679 0 : spectralAxis=CoordinateUtil::findSpectralAxis(csysHigh_p);
680 0 : Vector<Stokes::StokesTypes> stokesvec;
681 0 : stokesAxis=CoordinateUtil::findStokesAxis(stokesvec, csysHigh_p);
682 0 : Vector<Int> dirAxes=CoordinateUtil::findDirectionAxes(csysHigh_p);
683 0 : Int n3=highIm_p->shape()(stokesAxis);
684 0 : Int n4=highIm_p->shape()(spectralAxis);
685 0 : IPosition blc(highIm_p->shape());
686 0 : IPosition trc(highIm_p->shape());
687 0 : blc(dirAxes(0))=0; blc(dirAxes(1))=0;
688 0 : trc(dirAxes(0))=highIm_p->shape()(dirAxes(0))-1;
689 0 : trc(dirAxes(1))=highIm_p->shape()(dirAxes(1))-1;
690 0 : TempImage<Complex>cimagelow(lowIm_p->shape(), lowIm_p->coordinates());
691 0 : StokesImageUtil::From(cimagelow, *lowIm_p);
692 0 : LatticeFFT::cfft2d( cimagelow);
693 0 : Float sdScaling = sdScale_p*hBeam_p.getArea("arcsec2")/lBeam_p.getArea("arcsec2");
694 0 : for (Int j=0; j < n3; ++j){
695 0 : for (Int k=0; k < n4 ; ++k){
696 0 : blc(stokesAxis)=j; trc(stokesAxis)=j;
697 0 : blc(spectralAxis)=k; trc(spectralAxis)=k;
698 0 : Slicer sl(blc, trc, Slicer::endIsLast);
699 0 : SubImage<Complex> cimagehighSub(*cwHighIm_p, sl, true);
700 0 : SubImage<Complex> cimagelowSub(cimagelow, sl, true);
701 0 : cimagelowSub.copyData( (LatticeExpr<Complex>)((cimagehighSub + cimagelowSub * sdScaling)));
702 : }
703 : }
704 : // FT back to image plane
705 0 : LatticeFFT::cfft2d( cimagelow, false);
706 :
707 : // write to output image
708 0 : PagedImage<Float> featherImage(highIm_p->shape(), highIm_p->coordinates(), imagename );
709 0 : StokesImageUtil::To(featherImage, cimagelow);
710 0 : ImageUtilities::copyMiscellaneous(featherImage, *highIm_p);
711 0 : String maskofHigh=highIm_p->getDefaultMask();
712 0 : String maskofLow=lowIm_p->getDefaultMask();
713 0 : if(maskofHigh != String("")){
714 : //ImageUtilities::copyMask(featherImage, *highIm_p, "mask0", maskofHigh, AxesSpecifier());
715 : //featherImage.setDefaultMask("mask0");
716 0 : Imager::copyMask(featherImage, *highIm_p, maskofHigh);
717 0 : if(maskofLow != String("")){
718 0 : featherImage.pixelMask().copyData(LatticeExpr<Bool> (featherImage.pixelMask() && (lowIm_p->pixelMask())));
719 :
720 : }
721 : }
722 0 : else if(maskofLow != String("")){
723 : //ImageUtilities::copyMask(featherImage, *lowIm_p, "mask0", maskofLow, AxesSpecifier());
724 0 : Imager::copyMask(featherImage, *lowIm_p, maskofLow);
725 : }
726 :
727 0 : return true;
728 : }
729 :
730 0 : void Feather::applyDishDiam(ImageInterface<Complex>& image, GaussianBeam& beam, Float effDiam, ImageInterface<Float>& fftim, Vector<Quantity>& extraconv){
731 : /*
732 : MathFunc<Float> dd(SPHEROIDAL);
733 : Vector<Float> valsph(31);
734 : for(Int k=0; k <31; ++k){
735 : valsph(k)=dd.value((Float)(k)/10.0);
736 : }
737 : Quantity fulrad((52.3/2.0*3.0/1.1117),"arcsec");
738 : Quantity lefreq(224.0/effDiam*9.0, "GHz");
739 :
740 : PBMath1DNumeric elpb(valsph, fulrad, lefreq);*/
741 : ////////////////////////
742 : /*{
743 : PagedImage<Float> thisScreen(image.shape(), image.coordinates(), "Before_apply.image");
744 : LatticeExpr<Float> le(abs(image));
745 : thisScreen.copyData(le);
746 : }*/
747 : //////////////////////
748 :
749 0 : Double freq = worldFreq(image.coordinates(), 0);
750 : //cerr << "Freq " << freq << endl;
751 0 : Quantity halfpb=Quantity(1.22*C::c/freq/effDiam, "rad");
752 : //PBMath1DAiry elpb( Quantity(effDiam,"m"), Quantity(0.01,"m"),
753 : // Quantity(0.8564,"deg"), Quantity(1.0,"GHz"));
754 0 : GaussianBeam newBeam(halfpb, halfpb, Quantity(0.0, "deg"));
755 : try {
756 :
757 0 : GaussianBeam toBeUsed;
758 : //cerr << "beam " << beam.toVector() << endl;
759 : //cerr << "newBeam " << newBeam.toVector() << endl;
760 0 : GaussianDeconvolver::deconvolve(toBeUsed, newBeam, beam);
761 0 : extraconv.resize(3);
762 : // use the Major difference
763 0 : extraconv(0) = toBeUsed.getMajor();
764 0 : extraconv(1) = toBeUsed.getMinor();
765 0 : extraconv(2) = toBeUsed.getPA();
766 :
767 : }
768 0 : catch (const AipsError& x) {
769 0 : throw(AipsError("Beam due to new effective diameter may be smaller than the beam of original dish image"));
770 : }
771 : //////////////////////
772 : //1 GHz equivalent
773 : // halfpb=Quantity(1.22*C::c/1.0e9/effDiam, "rad");
774 : //cerr << "halfpb " << halfpb << endl;
775 : //PBMath1DGauss elpb(halfpb, Quantity(0.8564,"deg"), Quantity(1.0,"GHz"), true);
776 :
777 0 : fftim.set(0.0);
778 :
779 0 : IPosition center(4, Int((fftim.shape()(0)/4)*2),
780 0 : Int((fftim.shape()(1)/4)*2),0,0);
781 0 : fftim.putAt(1.0, center);
782 0 : StokesImageUtil::Convolve(fftim, newBeam, false);
783 0 : StokesImageUtil::From(image, fftim);
784 : /*
785 : TempImage<Complex> elbeamo(image.shape(), image.coordinates());
786 : elbeamo.set(1.0);
787 : MDirection wcenter;
788 : {
789 : Int directionIndex=
790 : image.coordinates().findCoordinate(Coordinate::DIRECTION);
791 : DirectionCoordinate
792 : directionCoord=image.coordinates().directionCoordinate(directionIndex);
793 : Vector<Double> pcenter(2);
794 : pcenter(0) = image.shape()(directionIndex)/2;
795 : pcenter(1) = image.shape()(directionIndex+1)/2;
796 : directionCoord.toWorld( wcenter, pcenter );
797 : }
798 : elpb.applyPB(elbeamo, elbeamo, wcenter, Quantity(0.0, "deg"),
799 : BeamSquint::NONE);
800 :
801 :
802 : StokesImageUtil::To(fftim, elbeamo);
803 : */
804 : ///////////////////
805 : //StokesImageUtil::FitGaussianPSF(fftim,
806 : // beam);
807 : //cerr << "To be convolved beam 2 " << beam.toVector() << endl;
808 : ////////////////
809 :
810 0 : LatticeFFT::cfft2d(image);
811 : //image.copyData((LatticeExpr<Complex>)(elbeamo) );
812 : //elbeamo.copyData(image);
813 : // LatticeFFT::cfft2d(elbeamo, false);
814 : //StokesImageUtil::To(fftim, elbeamo);
815 : //StokesImageUtil::FitGaussianPSF(fftim,
816 : // beam);
817 : /////////
818 : /*{
819 : PagedImage<Float> thisScreen(image.shape(), image.coordinates(), "After_apply.image");
820 : //LatticeExpr<Float> le(abs(image));
821 : thisScreen.copyData(fftim);
822 : }*/
823 : ////////
824 0 : }
825 :
826 :
827 : /*
828 : void Feather::feather(const String& image, const ImageInterface<Float>& high, const ImageInterface<Float>& low0, const Float& sdScale, const String& lowPSF, const Bool useDefaultPB, const String& vpTableStr, Float effDiam, const Bool doPlot){
829 :
830 : LogIO os(LogOrigin("Feather", "feather()", WHERE));
831 : try {
832 :
833 :
834 : GaussianBeam hBeam , lBeam;
835 : Vector<Quantity> extraconv;
836 : ImageInfo highInfo=high.imageInfo();
837 : hBeam=highInfo.restoringBeam();
838 : ImageInfo lowInfo=low0.imageInfo();
839 : lBeam=lowInfo.restoringBeam();
840 : if(hBeam.isNull()) {
841 : os << LogIO::WARN
842 : << "High resolution image does not have any resolution information - will be unable to scale correctly.\n"
843 : << LogIO::POST;
844 : }
845 :
846 : PBMath * myPBp = 0;
847 : if((lowPSF=="") && lBeam.isNull()) {
848 : // create the low res's PBMath object, needed to apply PB
849 : // to make high res Fourier weight image
850 : if (useDefaultPB) {
851 : // look up the telescope in ObsInfo
852 : ObsInfo oi = low0.coordinates().obsInfo();
853 : String myTelescope = oi.telescope();
854 : if (myTelescope == "") {
855 : os << LogIO::SEVERE << "No telescope imbedded in low res image"
856 : << LogIO::POST;
857 : os << LogIO::SEVERE << "Create a PB description with the vpmanager"
858 : << LogIO::EXCEPTION;
859 : }
860 : Quantity qFreq;
861 : {
862 : Double freq = worldFreq(low0.coordinates(), 0);
863 : qFreq = Quantity( freq, "Hz" );
864 : }
865 : String band;
866 : PBMath::CommonPB whichPB;
867 : String pbName;
868 : // get freq from coordinates
869 : PBMath::whichCommonPBtoUse (myTelescope, qFreq, band, whichPB,
870 : pbName);
871 : if (whichPB == PBMath::UNKNOWN) {
872 : os << LogIO::SEVERE << "Unknown telescope for PB type: "
873 : << myTelescope << LogIO::EXCEPTION;
874 : }
875 : myPBp = new PBMath(whichPB);
876 : } else {
877 : // get the PB from the vpTable
878 : Table vpTable( vpTableStr );
879 : ScalarColumn<TableRecord> recCol(vpTable, (String)"pbdescription");
880 : myPBp = new PBMath(recCol(0));
881 : }
882 : AlwaysAssert((myPBp != 0), AipsError);
883 : }
884 :
885 : // regrid the single dish image
886 : TempImage<Float> low(high.shape(), high.coordinates());
887 : {
888 : IPosition axes(2,0,1);
889 : if(high.shape().nelements() >2){
890 : Int spectralAxisIndex=high.coordinates().
891 : findCoordinate(Coordinate::SPECTRAL);
892 : if(spectralAxisIndex > -1){
893 : axes.resize(3);
894 : axes(0)=0;
895 : axes(1)=1;
896 : axes(2)=spectralAxisIndex+1;
897 : }
898 : }
899 : ImageRegrid<Float> ir;
900 : ir.regrid(low, Interpolate2D::LINEAR, axes, low0);
901 : }
902 :
903 : // get image center direction (needed for SD PB, which is needed for
904 : // the high res Fourier weight image
905 : MDirection wcenter;
906 : {
907 : Int directionIndex=
908 : high.coordinates().findCoordinate(Coordinate::DIRECTION);
909 : AlwaysAssert(directionIndex>=0, AipsError);
910 : DirectionCoordinate
911 : directionCoord=high.coordinates().directionCoordinate(directionIndex);
912 : Vector<Double> pcenter(2);
913 : pcenter(0) = high.shape()(0)/2;
914 : pcenter(1) = high.shape()(1)/2;
915 : directionCoord.toWorld( wcenter, pcenter );
916 : }
917 :
918 : // make the weight image for high res Fourier plane: 1 - normalized(FT(sd_PB))
919 : IPosition myshap(high.shape());
920 : for( uInt k=2; k< myshap.nelements(); ++k){
921 : myshap(k)=1;
922 : }
923 :
924 : TempImage<Float> lowpsf0;
925 : TempImage<Complex> cweight(myshap, high.coordinates());
926 : if(lowPSF=="") {
927 : os << LogIO::NORMAL // Loglevel INFO
928 : << "Using primary beam to determine weighting.\n" << LogIO::POST;
929 : if(lBeam.isNull()) {
930 : cweight.set(1.0);
931 : if (myPBp != 0) {
932 : myPBp->applyPB(cweight, cweight, wcenter, Quantity(0.0, "deg"),
933 : BeamSquint::NONE);
934 :
935 : lowpsf0=TempImage<Float>(cweight.shape(), cweight.coordinates());
936 :
937 : os << LogIO::NORMAL // Loglevel INFO
938 : << "Determining scaling from SD Primary Beam.\n"
939 : << LogIO::POST;
940 : StokesImageUtil::To(lowpsf0, cweight);
941 : StokesImageUtil::FitGaussianPSF(lowpsf0,
942 : lBeam);
943 : }
944 : delete myPBp;
945 : }
946 : else{
947 : os << LogIO::NORMAL // Loglevel INFO
948 : << "Determining scaling from SD restoring beam.\n"
949 : << LogIO::POST;
950 : lowpsf0=TempImage<Float>(cweight.shape(), cweight.coordinates());
951 : lowpsf0.set(0.0);
952 : IPosition center(4, Int((cweight.shape()(0)/4)*2),
953 : Int((cweight.shape()(1)/4)*2),0,0);
954 : lowpsf0.putAt(1.0, center);
955 : StokesImageUtil::Convolve(lowpsf0, lBeam, false);
956 : StokesImageUtil::From(cweight, lowpsf0);
957 :
958 : }
959 : }
960 : else {
961 : os << LogIO::NORMAL // Loglevel INFO
962 : << "Using specified low resolution PSF to determine weighting.\n"
963 : << LogIO::POST;
964 : // regrid the single dish psf
965 : PagedImage<Float> lowpsfDisk(lowPSF);
966 : IPosition lshape(lowpsfDisk.shape());
967 : lshape.resize(4);
968 : lshape(2)=1; lshape(3)=1;
969 : TempImage<Float>lowpsf(lshape,lowpsfDisk.coordinates());
970 : IPosition blc(lowpsfDisk.shape());
971 : IPosition trc(lowpsfDisk.shape());
972 : blc(0)=0; blc(1)=0;
973 : trc(0)=lowpsfDisk.shape()(0)-1;
974 : trc(1)=lowpsfDisk.shape()(1)-1;
975 : for( uInt k=2; k < lowpsfDisk.shape().nelements(); ++k){
976 : blc(k)=0; trc(k)=0;
977 : }// taking first plane
978 : Slicer sl(blc, trc, Slicer::endIsLast);
979 : lowpsf.copyData(SubImage<Float>(lowpsfDisk, sl, false));
980 : lowpsf0=TempImage<Float> (myshap, high.coordinates());
981 : {
982 : ImageRegrid<Float> ir;
983 : IPosition axes(2,0,1); // if its a cube, regrid the spectral too
984 : ir.regrid(lowpsf0, Interpolate2D::LINEAR, axes, lowpsf);
985 : }
986 : if(lBeam.isNull()) {
987 : os << LogIO::NORMAL // Loglevel INFO
988 : << "Determining scaling from low resolution PSF.\n" << LogIO::POST;
989 : StokesImageUtil::FitGaussianPSF(lowpsf, lBeam);
990 : }
991 : StokesImageUtil::From(cweight, lowpsf0);
992 : }
993 :
994 : LatticeFFT::cfft2d( cweight );
995 : if(effDiam >0.0){
996 : //cerr << "in effdiam" << effDiam << endl;
997 : applyDishDiam(cweight, lBeam, effDiam, lowpsf0, extraconv);
998 : lowpsf0.copyData((LatticeExpr<Float>)(lowpsf0/max(lowpsf0)));
999 : StokesImageUtil::FitGaussianPSF(lowpsf0, lBeam);
1000 :
1001 : Int directionIndex=
1002 : cweight.coordinates().findCoordinate(Coordinate::DIRECTION);
1003 : Image2DConvolver<Float>::convolve(
1004 : os, low, low, VectorKernel::toKernelType("gauss"), IPosition(2, directionIndex, directionIndex+1),
1005 : extraconv, true, 1.0, true
1006 : );
1007 :
1008 : }
1009 : LatticeExprNode node = max( cweight );
1010 : Float fmax = abs(node.getComplex());
1011 : cweight.copyData( (LatticeExpr<Complex>)( 1.0f - cweight/fmax ) );
1012 : //Plotting part
1013 : if(doPlot){
1014 : CoordinateSystem ftCoords(cweight.coordinates());
1015 : Double freq=worldFreq(ftCoords, 0);
1016 : ////
1017 : Int directionIndex=ftCoords.findCoordinate(Coordinate::DIRECTION);
1018 : Array<Complex> tmpval;
1019 : IPosition start=cweight.shape();
1020 : IPosition shape=cweight.shape()/2;
1021 : for(uInt k=0; k < shape.nelements(); ++k){
1022 : start[k]=0;
1023 : if(k != uInt(directionIndex+1))
1024 : shape[k]=1;
1025 : }
1026 : start[directionIndex+1]=cweight.shape()[directionIndex+1]/2;
1027 : start[directionIndex]=cweight.shape()[directionIndex]/2;
1028 : cweight.getSlice(tmpval, start, shape, true);
1029 : Vector<Float> x=amplitude(tmpval);
1030 : Vector<Float> xdish=(Float(1.0) - x)*Float(sdScale);
1031 : tmpval.resize();
1032 : shape=cweight.shape()/2;
1033 : for(uInt k=0; k < shape.nelements(); ++k){
1034 : start[k]=0;
1035 : if(k != uInt(directionIndex))
1036 : shape[k]=1;
1037 : }
1038 : start[directionIndex+1]=cweight.shape()[directionIndex+1]/2;
1039 : start[directionIndex]=cweight.shape()[directionIndex]/2;
1040 : cweight.getSlice(tmpval, start, shape, true);
1041 : Vector<Float> y=amplitude(tmpval);
1042 : Vector<Float> ydish=(Float(1.0)-y)*Float(sdScale);
1043 : DirectionCoordinate dc=ftCoords.directionCoordinate(directionIndex);
1044 : Vector<Bool> axes(2); axes(0)=true;axes(1)=true;
1045 : Vector<Int> elshape(2);
1046 : elshape(0)=cweight.shape()[directionIndex];
1047 : elshape(1)=cweight.shape()[directionIndex+1];
1048 : Coordinate* ftdc=dc.makeFourierCoordinate(axes,elshape);
1049 : Vector<Double> xpix(x.nelements());
1050 : indgen(xpix);
1051 : xpix +=Double(cweight.shape()[directionIndex])/2.0;
1052 : Matrix<Double> pix(2, xpix.nelements());
1053 : Matrix<Double> world(2, xpix.nelements());
1054 : Vector<Bool> failures;
1055 : pix.row(1)=elshape(0)/2;
1056 : pix.row(0)=xpix;
1057 : ftdc->toWorldMany(world, pix, failures);
1058 : xpix=world.row(0);
1059 : //cerr << "xpix " << xpix << endl;
1060 : xpix=fabs(xpix)*(C::c)/freq;
1061 : Vector<Double> ypix(y.nelements());
1062 : indgen(ypix);
1063 : ypix +=Double(cweight.shape()[directionIndex+1])/2.0;
1064 : pix.resize(2, ypix.nelements());
1065 : world.resize();
1066 : pix.row(1)=ypix;
1067 : pix.row(0)=elshape(1)/2;
1068 : ftdc->toWorldMany(world, pix, failures);
1069 : ypix=world.row(1);
1070 : ypix=fabs(ypix)*(C::c/freq);
1071 : PlotServerProxy *plotter = dbus::launch<PlotServerProxy>( );
1072 : dbus::variant panel_id = plotter->panel( "Feather function slice cuts", "Distance in m", "Amp", "Feather",
1073 : std::vector<int>( ), "right");
1074 :
1075 : if ( panel_id.type( ) != dbus::variant::INT ) {
1076 : os << LogIO::SEVERE << "failed to start plotter" << LogIO::POST;
1077 : return ;
1078 : }
1079 :
1080 :
1081 : plotter->line(dbus::af(xpix),dbus::af(x),"blue","x-interferometer weight",panel_id.getInt( ));
1082 : plotter->line(dbus::af(xpix),dbus::af(xdish),"cyan","x-singledish weight",panel_id.getInt( ));
1083 :
1084 : plotter->line(dbus::af(ypix),dbus::af(y),"green","y-interferometer weight",panel_id.getInt( ));
1085 : plotter->line(dbus::af(ypix),dbus::af(ydish),"purple","y-singledish weight",panel_id.getInt( ));
1086 :
1087 : }
1088 : //End plotting part
1089 : // FT high res image
1090 : TempImage<Complex> cimagehigh(high.shape(), high.coordinates() );
1091 : StokesImageUtil::From(cimagehigh, high);
1092 : LatticeFFT::cfft2d( cimagehigh );
1093 :
1094 : // FT low res image
1095 : TempImage<Complex> cimagelow(high.shape(), high.coordinates() );
1096 : StokesImageUtil::From(cimagelow, low);
1097 : LatticeFFT::cfft2d( cimagelow );
1098 :
1099 :
1100 : // This factor comes from the beam volumes
1101 : if(sdScale != 1.0)
1102 : os << LogIO::NORMAL // Loglevel INFO
1103 : << "Multiplying single dish data by user specified factor "
1104 : << sdScale << ".\n" << LogIO::POST;
1105 : Float sdScaling = sdScale;
1106 : if (! hBeam.isNull() && ! lBeam.isNull()) {
1107 :
1108 : Float beamFactor=
1109 : hBeam.getArea("arcsec2")/lBeam.getArea("arcsec2");
1110 : os << LogIO::NORMAL // Loglevel INFO
1111 : << "Applying additional scaling for ratio of the volumes of the high to the low resolution images : "
1112 : << beamFactor << ".\n" << LogIO::POST;
1113 : sdScaling*=beamFactor;
1114 : }
1115 : else {
1116 : os << LogIO::WARN << "Insufficient information to scale correctly.\n"
1117 : << LogIO::POST;
1118 : }
1119 :
1120 : // combine high and low res, appropriately normalized, in Fourier
1121 : // plane. The vital point to remember is that cimagelow is already
1122 : // multiplied by 1-cweight so we only need adjust for the ratio of beam
1123 : // volumes
1124 : Vector<Int> extraAxes(cimagehigh.shape().nelements()-2);
1125 : if(extraAxes.nelements() > 0){
1126 :
1127 : if(extraAxes.nelements() ==2){
1128 : Int n3=cimagehigh.shape()(2);
1129 : Int n4=cimagehigh.shape()(3);
1130 : IPosition blc(cimagehigh.shape());
1131 : IPosition trc(cimagehigh.shape());
1132 : blc(0)=0; blc(1)=0;
1133 : trc(0)=cimagehigh.shape()(0)-1;
1134 : trc(1)=cimagehigh.shape()(1)-1;
1135 : for (Int j=0; j < n3; ++j){
1136 : for (Int k=0; k < n4 ; ++k){
1137 : blc(2)=j; trc(2)=j;
1138 : blc(3)=k; trc(3)=k;
1139 : Slicer sl(blc, trc, Slicer::endIsLast);
1140 : SubImage<Complex> cimagehighSub(cimagehigh, sl, true);
1141 : SubImage<Complex> cimagelowSub(cimagelow, sl, true);
1142 : cimagehighSub.copyData( (LatticeExpr<Complex>)((cimagehighSub * cweight + cimagelowSub * sdScaling)));
1143 : }
1144 : }
1145 : }
1146 : }
1147 : else{
1148 : cimagehigh.copyData(
1149 : (LatticeExpr<Complex>)((cimagehigh * cweight
1150 : + cimagelow * sdScaling)));
1151 : }
1152 : // FT back to image plane
1153 : LatticeFFT::cfft2d( cimagehigh, false);
1154 :
1155 : // write to output image
1156 : PagedImage<Float> featherImage(high.shape(), high.coordinates(), image );
1157 : StokesImageUtil::To(featherImage, cimagehigh);
1158 : ImageUtilities::copyMiscellaneous(featherImage, high);
1159 :
1160 : try{
1161 : { // write data processing history into image logtable
1162 : LoggerHolder imagelog (false);
1163 : LogSink& sink = imagelog.sink();
1164 : LogOrigin lor(String("Feather"), String("feather()"));
1165 : LogMessage msg(lor);
1166 : ostringstream oos;
1167 : oos << endl << "Imager::feather() input paramaters:" << endl
1168 : << "Feathered image = '" << image << "'" << endl
1169 : << "High resolution image ='" << high.name() << "'" << endl
1170 : << "Low resolution image = '" << low0.name() << "'" << endl
1171 : << "Low resolution PSF = '" << lowPSF << "'" << endl << endl;
1172 : String inputs(oos);
1173 : sink.postLocally(msg.message(inputs));
1174 : imagelog.flush();
1175 :
1176 : LoggerHolder& log = featherImage.logger();
1177 : log.append(imagelog);
1178 : log.flush();
1179 : }
1180 : }catch(exception& x){
1181 :
1182 : os << LogIO::WARN << "Caught exception: " << x.what()
1183 : << LogIO::POST;
1184 :
1185 :
1186 : }
1187 : catch(...){
1188 : os << LogIO::SEVERE << "Unknown exception handled" << LogIO::POST;
1189 :
1190 : }
1191 :
1192 :
1193 :
1194 :
1195 :
1196 :
1197 :
1198 :
1199 : }catch(exception& x){
1200 :
1201 : os << LogIO::WARN << "Caught exception: " << x.what()
1202 : << LogIO::POST;
1203 : }
1204 :
1205 :
1206 :
1207 : }
1208 : */
1209 0 : void Feather::feather(const String& image, const ImageInterface<Float>& high, const ImageInterface<Float>& low0, const Float& sdScale, const String& lowPSF, const Bool useDefaultPB, const String& vpTableStr, Float effDiam, const Bool doHiPassFilterOnSD){
1210 :
1211 0 : Feather plume;
1212 0 : plume.setINTImage(high);
1213 0 : ImageInfo lowInfo=low0.imageInfo();
1214 0 : GaussianBeam lBeam=lowInfo.restoringBeam();
1215 0 : if(lBeam.isNull()) {
1216 0 : getLowBeam(low0, lowPSF, useDefaultPB, vpTableStr, lBeam);
1217 0 : if(lBeam.isNull())
1218 0 : throw(AipsError("Do not have low resolution beam info "));
1219 0 : TempImage<Float> newLow(low0.shape(), low0.coordinates());
1220 0 : newLow.copyData(low0);
1221 0 : lowInfo.removeRestoringBeam();
1222 0 : lowInfo.setRestoringBeam(lBeam);
1223 0 : newLow.setImageInfo(lowInfo);
1224 0 : plume.setSDImage(newLow);
1225 : }
1226 : else{
1227 0 : plume.setSDImage(low0);
1228 : }
1229 0 : plume.setSDScale(sdScale);
1230 0 : if(effDiam >0.0){
1231 0 : plume.setEffectiveDishDiam(effDiam, effDiam);
1232 : }
1233 0 : else if(doHiPassFilterOnSD){
1234 : Float xdiam, ydiam;
1235 0 : plume.getEffectiveDishDiam(xdiam, ydiam);
1236 0 : plume.setEffectiveDishDiam(xdiam, ydiam);
1237 : }
1238 0 : plume.saveFeatheredImage(image);
1239 :
1240 0 : }
1241 :
1242 :
1243 0 : void Feather::getLowBeam(const ImageInterface<Float>& low0, const String& lowPSF, const Bool useDefaultPB, const String& vpTableStr, GaussianBeam& lBeam){
1244 0 : LogIO os(LogOrigin("Feather", "getLowBeam()", WHERE));
1245 0 : PBMath * myPBp = 0;
1246 0 : if((lowPSF=="") && lBeam.isNull()) {
1247 : // create the low res's PBMath object, needed to apply PB
1248 : // to make high res Fourier weight image
1249 0 : if (useDefaultPB) {
1250 : // look up the telescope in ObsInfo
1251 0 : ObsInfo oi = low0.coordinates().obsInfo();
1252 0 : String myTelescope = oi.telescope();
1253 0 : if (myTelescope == "") {
1254 : os << LogIO::SEVERE << "No telescope imbedded in low res image"
1255 0 : << LogIO::POST;
1256 : os << LogIO::SEVERE << "Create a PB description with the vpmanager"
1257 0 : << LogIO::EXCEPTION;
1258 : }
1259 0 : Quantity qFreq;
1260 : {
1261 0 : Double freq = worldFreq(low0.coordinates(), 0);
1262 0 : qFreq = Quantity( freq, "Hz" );
1263 : }
1264 0 : String band;
1265 : PBMath::CommonPB whichPB;
1266 0 : String pbName;
1267 : // get freq from coordinates
1268 0 : PBMath::whichCommonPBtoUse (myTelescope, qFreq, band, whichPB,
1269 : pbName);
1270 0 : if (whichPB == PBMath::UNKNOWN) {
1271 : os << LogIO::SEVERE << "Unknown telescope for PB type: "
1272 0 : << myTelescope << LogIO::EXCEPTION;
1273 : }
1274 0 : myPBp = new PBMath(whichPB);
1275 : } else {
1276 : // get the PB from the vpTable
1277 0 : Table vpTable( vpTableStr );
1278 0 : ScalarColumn<TableRecord> recCol(vpTable, (String)"pbdescription");
1279 0 : myPBp = new PBMath(recCol(0));
1280 : }
1281 0 : AlwaysAssert((myPBp != 0), AipsError);
1282 : }
1283 :
1284 :
1285 : // get image center direction
1286 0 : MDirection wcenter;
1287 : {
1288 : Int directionIndex=
1289 0 : low0.coordinates().findCoordinate(Coordinate::DIRECTION);
1290 0 : AlwaysAssert(directionIndex>=0, AipsError);
1291 : DirectionCoordinate
1292 0 : directionCoord=low0.coordinates().directionCoordinate(directionIndex);
1293 0 : Vector<Double> pcenter(2);
1294 0 : pcenter(0) = low0.shape()(0)/2;
1295 0 : pcenter(1) = low0.shape()(1)/2;
1296 0 : directionCoord.toWorld( wcenter, pcenter );
1297 : }
1298 :
1299 : // make the weight image
1300 0 : IPosition myshap(low0.shape());
1301 0 : for( uInt k=2; k< myshap.nelements(); ++k){
1302 0 : myshap(k)=1;
1303 : }
1304 :
1305 0 : TempImage<Float> lowpsf0;
1306 0 : TempImage<Complex> cweight(myshap, low0.coordinates());
1307 0 : if(lowPSF=="") {
1308 : os << LogIO::NORMAL // Loglevel INFO
1309 0 : << "Using primary beam to determine weighting.\n" << LogIO::POST;
1310 0 : cweight.set(1.0);
1311 0 : if (myPBp != 0) {
1312 0 : myPBp->applyPB(cweight, cweight, wcenter, Quantity(0.0, "deg"),
1313 0 : BeamSquint::NONE);
1314 :
1315 0 : lowpsf0=TempImage<Float>(cweight.shape(), cweight.coordinates());
1316 :
1317 : os << LogIO::NORMAL // Loglevel INFO
1318 : << "Determining scaling from SD Primary Beam.\n"
1319 0 : << LogIO::POST;
1320 0 : StokesImageUtil::To(lowpsf0, cweight);
1321 0 : StokesImageUtil::FitGaussianPSF(lowpsf0,
1322 : lBeam);
1323 : }
1324 0 : delete myPBp;
1325 : }
1326 : else {
1327 : os << LogIO::NORMAL // Loglevel INFO
1328 : << "Using specified low resolution PSF to determine weighting.\n"
1329 0 : << LogIO::POST;
1330 : // regrid the single dish psf
1331 0 : PagedImage<Float> lowpsfDisk(lowPSF);
1332 0 : IPosition lshape(lowpsfDisk.shape());
1333 0 : lshape.resize(4);
1334 0 : lshape(2)=1; lshape(3)=1;
1335 0 : TempImage<Float>lowpsf(lshape,lowpsfDisk.coordinates());
1336 0 : IPosition blc(lowpsfDisk.shape());
1337 0 : IPosition trc(lowpsfDisk.shape());
1338 0 : blc(0)=0; blc(1)=0;
1339 0 : trc(0)=lowpsfDisk.shape()(0)-1;
1340 0 : trc(1)=lowpsfDisk.shape()(1)-1;
1341 0 : for( uInt k=2; k < lowpsfDisk.shape().nelements(); ++k){
1342 0 : blc(k)=0; trc(k)=0;
1343 : }// taking first plane
1344 0 : Slicer sl(blc, trc, Slicer::endIsLast);
1345 0 : lowpsf.copyData(SubImage<Float>(lowpsfDisk, sl, false));
1346 : os << LogIO::NORMAL // Loglevel INFO
1347 0 : << "Determining scaling from low resolution PSF.\n" << LogIO::POST;
1348 0 : StokesImageUtil::FitGaussianPSF(lowpsf, lBeam);
1349 : }
1350 :
1351 :
1352 :
1353 0 : }
1354 :
1355 0 : Double Feather::worldFreq(const CoordinateSystem& cs, Int spectralpix){
1356 : ///freq part
1357 0 : Int spectralIndex=cs.findCoordinate(Coordinate::SPECTRAL);
1358 : SpectralCoordinate
1359 : spectralCoord=
1360 0 : cs.spectralCoordinate(spectralIndex);
1361 0 : Vector<String> units(1); units = "Hz";
1362 0 : spectralCoord.setWorldAxisUnits(units);
1363 0 : Vector<Double> spectralWorld(1);
1364 0 : Vector<Double> spectralPixel(1);
1365 0 : spectralPixel(0) = spectralpix;
1366 0 : spectralCoord.toWorld(spectralWorld, spectralPixel);
1367 0 : Double freq = spectralWorld(0);
1368 0 : return freq;
1369 : }
1370 :
1371 :
1372 :
1373 :
1374 :
1375 : }//# NAMESPACE CASA - END
|