LCOV - code coverage report
Current view: top level - synthesis/TransformMachines - ALMAAperture.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 0 460 0.0 %
Date: 2024-10-10 19:51:30 Functions: 0 19 0.0 %

          Line data    Source code
       1             : //# ALMAAperture.cc: Implementation of the ALMAAperture class
       2             : //# Copyright (C) 1997,1998,1999,2000,2001,2002,2003
       3             : //# Associated Universities, Inc. Washington DC, USA.
       4             : //# Copyright (C) 2011 by ESO (in the framework of the ALMA collaboration)
       5             : //#
       6             : //# This library is free software; you can redistribute it and/or modify it
       7             : //# under the terms of the GNU Library General Public License as published by
       8             : //# the Free Software Foundation; either version 2 of the License, or (at your
       9             : //# option) any later version.
      10             : //#
      11             : //# This library is distributed in the hope that it will be useful, but WITHOUT
      12             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
      14             : //# License for more details.
      15             : //#
      16             : //# You should have received a copy of the GNU Library General Public License
      17             : //# along with this library; if not, write to the Free Software Foundation,
      18             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      19             : //#
      20             : //# Correspondence concerning AIPS++ should be addressed as follows:
      21             : //#        Internet email: casa-feedback@nrao.edu.
      22             : //#        Postal address: AIPS++ Project Office
      23             : //#                        National Radio Astronomy Observatory
      24             : //#                        520 Edgemont Road
      25             : //#                        Charlottesville, VA 22903-2475 USA
      26             : //#
      27             : //# $Id$
      28             : //
      29             : #include <synthesis/TransformMachines/Utils.h>
      30             : #include <synthesis/TransformMachines/ALMAAperture.h>
      31             : #include <synthesis/TransformMachines/SynthesisError.h>
      32             : #include <synthesis/TransformMachines/BeamCalc.h>
      33             : #include <synthesis/TransformMachines/WTerm.h>
      34             : #include <synthesis/TransformMachines/ALMACalcIlluminationConvFunc.h>
      35             : #include <casacore/coordinates/Coordinates/DirectionCoordinate.h>
      36             : #include <casacore/coordinates/Coordinates/SpectralCoordinate.h>
      37             : #include <casacore/coordinates/Coordinates/StokesCoordinate.h>
      38             : 
      39             : using namespace casacore;
      40             : namespace casa{
      41             : 
      42             :   AntennaResponses* ALMAAperture::aR_p = 0;
      43             :   Bool ALMAAperture::orderMattersInCFKey = false;
      44             : 
      45           0 :   ALMAAperture::ALMAAperture(): 
      46             :     //    ATerm(),
      47             :     AzElAperture(),
      48           0 :     polMap_p(),
      49           0 :     antTypeMap_p(),
      50           0 :     respImage_p()
      51             :   {
      52             : 
      53           0 :     haveCannedResponses_p = true;
      54             :     
      55           0 :     if(!aR_p){
      56           0 :       aR_p = new AntennaResponses();
      57             :     }
      58             : 
      59           0 :     if(!aR_p->isInit()){ // the shared antenna responses object was not yet initialised
      60             : 
      61           0 :       cout << "Initialising antenna responses ..." << endl;
      62             : 
      63           0 :       String antRespPath;
      64           0 :       if(!MeasTable::AntennaResponsesPath(antRespPath, "ALMA")) {
      65             :         // unknown observatory
      66           0 :         logIO() << LogOrigin("ALMAAperture", "ctor")
      67             :                 << LogIO::WARN
      68             :                 << "We don't have any precalculated antenna responses for ALMA."
      69             :                 << endl << "Will try to generate them using ray tracing instead."
      70           0 :                 << LogIO::POST;
      71           0 :         haveCannedResponses_p = false;
      72             :       }
      73           0 :       else if(!aR_p->init(antRespPath)){
      74             :         // init failed
      75           0 :         String mesg="Initialisation of antenna responses for observatory ALMA failed using path "+antRespPath;
      76           0 :         SynthesisError err(mesg);
      77           0 :         throw(err);
      78           0 :       }
      79           0 :       else if(MeasTable::AntennaResponsesPath(antRespPath, "ACA")) {
      80             :         // also have responses for ACA
      81           0 :         aR_p->append(antRespPath); // dont't throw if this fails because the ACA antennas
      82             :                                   // may already be in the ALMA table
      83             :       }
      84           0 :     }
      85             :          
      86           0 :   }
      87             :   
      88           0 :   ALMAAperture::~ALMAAperture(){ 
      89           0 :     for(uInt i=0;i<respImage_p.nelements();i++){
      90           0 :       if(respImage_p(i)){
      91           0 :         delete respImage_p(i);
      92             :       } 
      93             :     }
      94           0 :   };
      95             : 
      96             : 
      97           0 :   ALMAAperture& ALMAAperture::operator=(const ALMAAperture& other)
      98             :   {
      99           0 :     if(this!=&other) 
     100             :       {
     101             :         // aR_p does not need to be copied because it is static
     102           0 :         haveCannedResponses_p = other.haveCannedResponses_p;
     103           0 :         polMap_p.assign(other.polMap_p);
     104           0 :         antTypeMap_p.assign(other.antTypeMap_p);
     105             :       }
     106           0 :     return *this;
     107             :   }
     108           0 :   void ALMAAperture::cacheVBInfo(const String& telescopeName, 
     109             :                                  const Float& diameter)
     110             :   {
     111           0 :     telescopeName_p=telescopeName;
     112           0 :     Diameter_p=diameter;
     113           0 :   }
     114           0 :   void ALMAAperture::cacheVBInfo(const VisBuffer& vb)
     115             :   {
     116           0 :     Vector<String> telescopeNames=vb.msColumns().observation().telescopeName().getColumn();
     117           0 :     for(uInt nt=0;nt<telescopeNames.nelements();nt++){
     118           0 :       if ((telescopeNames(nt) != "ALMA") && 
     119           0 :           (telescopeNames(nt) != "ACA") && 
     120           0 :           (telescopeNames(nt) != "OSF")){
     121           0 :         String mesg="Can handle only ALMA, ACA, and OSF antennas.\n";
     122           0 :         mesg += "Erroneous telescope name = " + telescopeNames(nt) + ".";
     123           0 :         SynthesisError err(mesg);
     124           0 :         throw(err);
     125           0 :       }
     126             :     }
     127           0 :     telescopeName_p=telescopeNames[0];
     128           0 :   }
     129             : 
     130           0 :   Int ALMAAperture::getBandID(const Double& freq, const String& /*telescopeName*/)
     131             :   {
     132           0 :     Int bandID = -1;
     133           0 :     if(haveCannedResponses_p){
     134           0 :       String bandName;
     135           0 :       if(aR_p->getBandName(bandName, "ALMA", freq)){
     136           0 :         bandID = atoi(bandName.substr(bandName.find("and")+3).c_str()); // band names start with "band" 
     137             :       }
     138             :       else{
     139           0 :         logIO() << LogOrigin("ALMAAperture", "getVisParams")
     140             :                 << LogIO::WARN
     141             :                 << "We don't have predefined antenna responses for ALMA at "
     142             :                 << freq << " Hz. Will try to use raytracing instead."
     143           0 :                 << LogIO::POST;
     144             :       }      
     145           0 :     }
     146           0 :     return bandID;
     147             :   }
     148             : 
     149           0 :   Int ALMAAperture::getVisParams(const VisBuffer& vb, 
     150             :                                  const CoordinateSystem& /*skyCoord*/)
     151             :   {
     152           0 :     cacheVBInfo(vb);
     153             : 
     154           0 :     MVFrequency FreqQ(vb.msColumns().spectralWindow().refFrequencyQuant()(0));
     155           0 :     Double Freq = FreqQ.getValue();
     156             : 
     157           0 :     return getBandID(Freq, telescopeName_p);
     158             : 
     159             :     // Int bandID = -1;
     160             :     // if(haveCannedResponses_p){
     161             :     //   String bandName;
     162             :     //   if(aR_p->getBandName(bandName, "ALMA", FreqQ)){
     163             :     //  bandID = atoi(bandName.substr(bandName.find("and")+3).c_str()); // band names start with "band" 
     164             :     //   }
     165             :     //   else{
     166             :     //  logIO() << LogOrigin("ALMAAperture", "getVisParams")
     167             :     //          << LogIO::WARN
     168             :     //          << "We don't have predefined antenna responses for ALMA at "
     169             :     //          << Freq << " Hz. Will try to use raytracing instead."
     170             :     //          << LogIO::POST;
     171             :     //   }      
     172             :     // }
     173             :     // return bandID;
     174           0 :   }
     175             :   
     176           0 :   void ALMAAperture::makeFullJones(ImageInterface<Complex>& /*pbImage*/,
     177             :                                    const VisBuffer& /*vb*/,
     178             :                                    Bool /*doSquint*/, Int& /*bandID*/, Double /*freqVal*/)
     179             :   {
     180           0 :     throw(AipsError("ALMAAperture::makeJones() not yet implemented"));
     181             :   }
     182             :   
     183           0 :   void ALMAAperture::applySky(ImageInterface<Complex>& outImage,  // the image (cube if there is more than one pol)
     184             :                                                                    // upon return: FTed convolution pair of AIFs given by the cfKey  
     185             :                                                                    // rotated by the PA and regridded to the image
     186             :                               const VisBuffer& vb, // for the parallactic angle
     187             :                               const Bool doSquint,
     188             :                               const Int& cfKey,
     189             :                               const Bool raytrace)
     190             :   {
     191             : 
     192           0 :     if(getVisParams(vb)==-1 || raytrace){ // need to use ray tracing
     193           0 :       ALMACalcIlluminationConvFunc almaPB;
     194           0 :       Long cachesize=(HostInfo::memoryTotal(true)/8)*1024;
     195           0 :       almaPB.setMaximumCacheSize(cachesize);
     196           0 :       almaPB.applyPB(outImage, vb, doSquint, cfKey);
     197           0 :     }
     198             :     else{ // use canned antenna responses
     199             : 
     200             :       //   (issue warning if image too coarse => will be in method ATerm::OK(vb, PAtolerance, timetolerance)
     201             :       
     202             :       //   identify the right response image based on antenna, freq band, polarizations
     203           0 :       Vector<ALMAAntennaType> aTypes = antennaTypesFromCFKey(cfKey);
     204           0 :       uInt nAntTypes = aTypes.nelements();
     205           0 :       Int spwId = vb.spectralWindow();
     206             : 
     207           0 :       Vector<String> respImageName(nAntTypes);
     208           0 :       Vector<uInt> respImageChannel(nAntTypes);
     209           0 :       Vector<MFrequency> respImageNomFreq(nAntTypes);
     210           0 :       Vector<AntennaResponses::FuncTypes> respImageFType(nAntTypes);
     211           0 :       Vector<MVAngle> respImageRotOffset(nAntTypes);
     212           0 :       Vector<Vector<Array<Complex> > > respByPol(nAntTypes); 
     213             : 
     214           0 :       MFrequency refFreq = vb.msColumns().spectralWindow().refFrequencyMeas()(spwId);
     215           0 :       MEpoch obsTime = vb.msColumns().observation().timeRangeMeas()(vb.observationId()(0))(IPosition(1,0)); // start time
     216           0 :       MDirection obsDir = vb.msColumns().field().phaseDirMeas(vb.fieldId()); 
     217             : 
     218           0 :       for(uInt i=0; i<nAntTypes; i++){
     219           0 :         cout << "Looking for ant type \"" << antTypeStrFromType(aTypes(i)) << "\", freq " 
     220           0 :              << refFreq.get(Unit("Hz")).getValue() << " Hz" << endl;
     221           0 :         if(!aR_p->getImageName(respImageName(i),
     222           0 :                                respImageChannel(i),
     223             :                                respImageNomFreq(i),
     224             :                                respImageFType(i),
     225             :                                respImageRotOffset(i),
     226             :                                "ALMA",
     227             :                                obsTime,
     228             :                                refFreq,
     229           0 :                                AntennaResponses::EFP, 
     230           0 :                                antTypeStrFromType(aTypes(i)),
     231             :                                obsDir,
     232             :                                "", // receiver type
     233           0 :                                0 // beam number
     234             :                                )){ // no matching response found
     235           0 :           ostringstream oss;
     236           0 :           oss << "No matching antenna response found for frequency "
     237           0 :               << refFreq.get(Unit("Hz")).getValue() << " Hz, and antenna type "
     238           0 :               << antTypeStrFromType(aTypes(i));
     239           0 :           throw(SynthesisError(oss.str()));
     240           0 :         }
     241             :       }
     242             : 
     243             :       // load all necessary images (max. two)
     244           0 :       for(uInt i=0; i<nAntTypes; i++){
     245           0 :         if(respImageFType(i)!=AntennaResponses::EFP){
     246           0 :           throw(SynthesisError(String("Can only process antenna responses of type EFP.")));
     247             :         }
     248             :       }
     249           0 :       respImage_p.resize(nAntTypes);
     250           0 :       for(uInt i=0; i<nAntTypes; i++){
     251           0 :         cout << "Loading " << respImageName(i) << endl;
     252             :         
     253             :         try{
     254           0 :           respImage_p(i) = new PagedImage<Complex>(respImageName(i));
     255             :         }
     256           0 :         catch(std::exception x){
     257           0 :           ostringstream oss;
     258           0 :           oss << "Error reading antenna response image from path \""
     259           0 :               << respImageName(i) << "\": " << x.what();
     260           0 :           respImage_p.resize(i,true);
     261           0 :           throw(SynthesisError(oss.str()));
     262           0 :         } 
     263             :       }
     264           0 :       cout << "Loaded " << nAntTypes << " images." << endl;
     265             : 
     266             : 
     267             : 
     268             :       // check if there are spectral and stokes axes in the output image
     269           0 :       Int pIndex = outImage.coordinates().findCoordinate(Coordinate::STOKES);
     270           0 :       if(pIndex==-1){
     271           0 :           ostringstream oss;
     272           0 :           oss << "Error: input image does not contain the necessary polarisation axis.";
     273           0 :           throw(SynthesisError(oss.str()));
     274           0 :       } 
     275           0 :       Int pSIndex = outImage.coordinates().findCoordinate(Coordinate::SPECTRAL);
     276             : 
     277             :       // identify polarisations in the response image and fill into respByPol(i)
     278           0 :       Int rIndex = respImage_p(0)->coordinates().findCoordinate(Coordinate::STOKES);
     279           0 :       Int rAxis = respImage_p(0)->coordinates().pixelAxes(rIndex)(0);
     280           0 :       Vector<Int> rStokes = respImage_p(0)->coordinates().stokesCoordinate(rIndex).stokes();
     281           0 :       IPosition rShape = respImage_p(0)->shape();
     282           0 :       if( (nAntTypes>1) && rShape != respImage_p(1)->shape()){
     283           0 :         ostringstream oss;
     284           0 :         oss << "Error: response images for different antenna types (but otherwise identical parameters)"
     285           0 :             << endl << "need to have the same shape:"
     286           0 :             << "Resp. image 1 shape " << rShape << endl
     287           0 :             << "Resp. image 2 shape " << respImage_p(1)->shape() << endl;
     288           0 :         throw(SynthesisError(oss.str()));
     289           0 :       } 
     290             :           
     291           0 :       const uInt rNDim = rShape.size();
     292             : 
     293           0 :       IPosition rSkyShape(rNDim,1);
     294           0 :       rSkyShape(0) = rShape(0);
     295           0 :       rSkyShape(1) = rShape(1);
     296           0 :       uInt nRPol = rStokes.nelements();
     297           0 :       if(!(nRPol==4 && 
     298           0 :            rStokes(0)==Stokes::XX && rStokes(1)==Stokes::XY && rStokes(2)==Stokes::YX && rStokes(3)==Stokes::YY)){
     299           0 :           ostringstream oss;
     300           0 :           oss << "Error: Antenna response image from path \""
     301           0 :               << respImageName(0) 
     302             :               << "\" does not contain the necessary polarisation products or they are in the wrong order.\n"
     303           0 :               << "Order should be XX, XY, YX, YY.";
     304           0 :           throw(SynthesisError(oss.str()));
     305           0 :       } 
     306           0 :       for(uInt i=0;i<nAntTypes; i++){ 
     307           0 :         respByPol(i).resize(nRPol); 
     308             :       }
     309           0 :       for(uInt i=0; i<nAntTypes; i++){
     310           0 :         for(uInt iPol=0; iPol<nRPol; iPol++){
     311           0 :           IPosition start(rNDim,0);
     312           0 :           start(rAxis) = iPol;
     313           0 :           respImage_p(i)->getSlice(respByPol(i)(iPol), start, rSkyShape); 
     314           0 :         }
     315             :       }
     316             : 
     317             :       // identify polarizations in the input image, put them into polToDoIndex()
     318           0 :       Vector<Int> inStokes;
     319           0 :       inStokes = outImage.coordinates().stokesCoordinate(pIndex).stokes();
     320           0 :       uInt nPol = inStokes.nelements();
     321           0 :       Vector<uInt> polToDoIndex(nPol);
     322           0 :       for(uInt i=0; i<nPol; i++){
     323           0 :         uInt ival=-1;
     324           0 :         switch(inStokes(i)){
     325           0 :         case Stokes::XX:
     326           0 :           ival = 0;
     327           0 :           break;
     328           0 :         case Stokes::XY:
     329           0 :           ival = 1;
     330           0 :           break;
     331           0 :         case Stokes::YX:
     332           0 :           ival = 2;
     333           0 :           break;
     334           0 :         case Stokes::YY:
     335           0 :           ival = 3;
     336           0 :           break;
     337           0 :         default:
     338           0 :           ostringstream oss;
     339           0 :           oss << "Error processing input image: polarization not valid for ALMA: " 
     340           0 :               << Stokes::name(Stokes::type(inStokes(i)));
     341           0 :           throw(SynthesisError(oss.str()));
     342             :           break;
     343             :         }
     344           0 :         polToDoIndex(i) = ival;
     345             :       }
     346             : 
     347             :       // Calculate the primary beam for the given baseline type for each polarization
     348           0 :       LogIO os(LogOrigin("ALMAAperture", "applySky", WHERE));
     349             :       
     350           0 :       CoordinateSystem dCoord = respImage_p(0)->coordinates(); // assume both response images have same coordsys
     351             : 
     352           0 :       CoordinateSystem dCoordFinal(dCoord);
     353           0 :       uInt rNDimFinal = rNDim;
     354           0 :       IPosition dShapeFinal = respImage_p(0)->shape();
     355           0 :       dShapeFinal(rAxis) = nPol; // set the number of stokes pixels to that of the output image
     356             : 
     357             :       // check if we need to add a degenerate spectral axis to the response image
     358           0 :       Int rSIndex = dCoord.findCoordinate(Coordinate::SPECTRAL);
     359           0 :       if(rSIndex==-1 && pSIndex!=-1){// no spectral coordinate in resp. image but input has one
     360           0 :         SpectralCoordinate sC;
     361           0 :         dCoordFinal.addCoordinate(sC);
     362           0 :         rSIndex = dCoordFinal.findCoordinate(Coordinate::SPECTRAL);
     363           0 :         dShapeFinal.resize(4,true);
     364           0 :         dShapeFinal(3)=1;
     365           0 :         rNDimFinal +=1;
     366           0 :       }
     367           0 :       else if(rSIndex!=-1 && pSIndex==-1){ // no spectral coordinate in input image but response has one
     368           0 :         dCoordFinal = CoordinateSystem();
     369           0 :         dCoordFinal.addCoordinate(dCoord.directionCoordinate(dCoord.findCoordinate(Coordinate::DIRECTION))); 
     370           0 :         dCoordFinal.addCoordinate(dCoord.stokesCoordinate(dCoord.findCoordinate(Coordinate::STOKES))); 
     371           0 :         dShapeFinal.resize(3,true);
     372           0 :         rNDimFinal -=1;
     373           0 :         rSIndex = -1;
     374             :       }
     375             : 
     376           0 :       TempImage<Complex> nearFinal(dShapeFinal, dCoordFinal);
     377             : 
     378           0 :       for(uInt iPol=0; iPol<nPol; iPol++){
     379             : 
     380           0 :         Array<Complex> pB( respByPol(0)(polToDoIndex(iPol)).shape() );
     381           0 :         Array<Complex> fact1( pB.shape() );
     382           0 :         Array<Complex> fact2( pB.shape() );
     383             : 
     384             :         // rotate the two factor arrays into the right PA
     385           0 :         Double dAngleRad = getPA(vb);
     386           0 :         cout << "PA = " << dAngleRad << " rad" << endl;
     387             : 
     388           0 :         Int fact1Index=-1, fact2Index=-1;
     389             :         Double pA1, pA2;
     390             : 
     391             :         // apply the rotation offset from the response table
     392           0 :         pA1 = dAngleRad + respImageRotOffset(0).radian();
     393           0 :         pA2 = dAngleRad + respImageRotOffset(nAntTypes-1).radian();
     394             : 
     395           0 :         switch(polToDoIndex(iPol)){
     396           0 :         case 0: // XX
     397           0 :           fact1Index = fact2Index = 0;
     398           0 :           break;
     399           0 :         case 1: //XY
     400           0 :           fact1Index = 0;
     401           0 :           fact2Index = 3;
     402           0 :           break;
     403           0 :         case 2: //YX
     404           0 :           fact1Index = 3;
     405           0 :           fact2Index = 0;
     406           0 :           break;
     407           0 :         case 3: //YY
     408           0 :           fact1Index = fact2Index = 3;
     409           0 :           break;
     410             :         }
     411             :           
     412           0 :         if(pA1 != pA2){ // rotate individual factors before multiplication
     413             : 
     414             :           // rotate factor 1
     415           0 :           SynthesisUtils::rotateComplexArray(os, respByPol(0)(fact1Index), dCoord, fact1, 
     416             :                                              pA1, "LINEAR", 
     417             :                                              false); // don't modify dCoord
     418             :           // if necessary rotate factor 2 
     419           0 :           if((nAntTypes-1)==0 &&  fact2Index==fact1Index){ // also implies that pA1==PA2
     420           0 :             fact2.assign(fact1);
     421             :           }
     422             :           else{
     423           0 :             SynthesisUtils::rotateComplexArray(os, respByPol(nAntTypes-1)(fact2Index), dCoord, fact2, 
     424             :                                                pA2, "LINEAR", 
     425             :                                                false); // don't modify dCoord
     426             :           }
     427             :         }
     428             :         else{ // rotate PB later
     429           0 :           fact1.assign(respByPol(0)(fact1Index));
     430           0 :           fact2.assign(respByPol(nAntTypes-1)(fact2Index));
     431             :         }
     432             : 
     433             :         // multiply EFPs (equivalent to convolution of AIFs) to get primary beam
     434           0 :         if(doSquint){
     435           0 :           pB = fact1 * conj(fact2);
     436             :         }
     437             :         else{
     438           0 :           pB = abs(fact1) * abs(fact2);
     439             :         }
     440             : 
     441             :         // now have the primary beam for polarization iPol in pB
     442             : 
     443             :         // combine all PBs into one image
     444           0 :         IPosition pos(rNDimFinal,0);
     445           0 :         pos(rAxis) = iPol;
     446             : 
     447           0 :         if(pA1 == pA2){ // still need to rotate pB by PA
     448             : 
     449           0 :           Array<Complex> pBrot( pB.shape() );
     450           0 :           SynthesisUtils::rotateComplexArray(os, pB, dCoord, pBrot, 
     451             :                                              pA1, "LINEAR", 
     452             :                                              false); // don't modify dCoord
     453           0 :           nearFinal.putSlice(pBrot, pos);  
     454             : 
     455           0 :         }
     456             :         else{ // pB was already rotated above
     457           0 :           nearFinal.putSlice(pB, pos);  
     458             :         }      
     459             : 
     460           0 :       }
     461             : 
     462             :       // Then regrid it to the image
     463             : 
     464             :       // The following mess is necessary since ImageRegrid does not work for Complex images
     465             :       // (Interpolate2D is not templated)
     466             : 
     467           0 :       Array<Complex> nearFinalArray = nearFinal.get();
     468             : 
     469           0 :       CoordinateSystem outCS(outImage.coordinates());
     470           0 :       Vector<Int> pixAxes=outCS.pixelAxes(outCS.findCoordinate(Coordinate::DIRECTION));
     471           0 :       IPosition whichOutPixelAxes(pixAxes);
     472             : 
     473             :       // get the world coordinates of the center of outImage
     474           0 :       Vector<Double> wCenterOut(2);
     475           0 :       Vector<Double> pCenterOut(2);
     476           0 :       pCenterOut(0) = outImage.shape()(whichOutPixelAxes(0))/2.-0.5;
     477           0 :       pCenterOut(1) = outImage.shape()(whichOutPixelAxes(1))/2.-0.5;
     478           0 :       Vector<String> wAU = outCS.directionCoordinate(0).worldAxisUnits();
     479           0 :       outCS.directionCoordinate(0).toWorld(wCenterOut, pCenterOut);
     480             :       //cout << "pixel center " << pCenterOut << " world center " << wCenterOut << " " << wAU(0) << endl;
     481             : 
     482           0 :       uInt dirCoordIndex = dCoordFinal.findCoordinate(Coordinate::DIRECTION);
     483             : 
     484             :       // convert direction coordinate to J2000 if necessary
     485           0 :       if(dCoordFinal.directionCoordinate(dirCoordIndex).directionType() != MDirection::J2000){
     486           0 :         Vector<Double> incrV = dCoordFinal.directionCoordinate(dirCoordIndex).increment();
     487           0 :         Vector<Double> refPV = dCoordFinal.directionCoordinate(dirCoordIndex).referencePixel();
     488           0 :         Vector<String> wAxUnitsV =  dCoordFinal.directionCoordinate(dirCoordIndex).worldAxisUnits();
     489           0 :         Projection pproj = dCoordFinal.directionCoordinate(dirCoordIndex).projection();
     490           0 :         Matrix<Double> xxform = dCoordFinal.directionCoordinate(dirCoordIndex).linearTransform();
     491           0 :         Quantity incr0(incrV(0),wAxUnitsV(0)); 
     492           0 :         Quantity incr1(incrV(1),wAxUnitsV(1)); 
     493             : 
     494             :         DirectionCoordinate newDC(MDirection::J2000, pproj, 0., 0., 
     495           0 :                                   incr0.getValue(Unit("rad")), incr1.getValue(Unit("rad")),
     496           0 :                                   xxform, refPV(0), refPV(1), 0., 90.);
     497           0 :         if(!dCoordFinal.replaceCoordinate(newDC, dirCoordIndex)){
     498           0 :           ostringstream oss;
     499           0 :           oss << "Error: response image direction coordinate cannot be set to direction type J2000.";
     500           0 :           throw(SynthesisError(oss.str()));
     501           0 :         }
     502           0 :       }
     503             : 
     504           0 :       DirectionCoordinate dCoordFinalDir = dCoordFinal.directionCoordinate(0);
     505             : 
     506             :       // Scale response image with frequency
     507           0 :       Unit uHz("Hz");
     508           0 :       Double refFreqHz = MFrequency::Convert(refFreq, MFrequency::TOPO)().get(uHz).getValue();
     509           0 :       Double nomFreqHz = MFrequency::Convert(respImageNomFreq(0), MFrequency::TOPO)().get(uHz).getValue();
     510           0 :       if(refFreqHz<=0.){
     511           0 :          throw(SynthesisError("Reference frequency in input image is <=0."));
     512             :       }
     513           0 :       Double fScale = nomFreqHz/refFreqHz;
     514           0 :       Vector<Double> newIncr = dCoordFinalDir.increment();
     515           0 :       cout << "Image increment before freq scaling " << newIncr << ", after scaling " << newIncr * fScale << endl;
     516           0 :       dCoordFinalDir.setIncrement(newIncr * fScale);
     517             : 
     518             :       // and set the reference Value of inImage to the world center of the outImage
     519           0 :       Vector<String> wAUI = dCoordFinalDir.worldAxisUnits();
     520           0 :       if(!(wAU(0)==wAUI(0))){
     521           0 :         Unit uIn(wAU(0));
     522           0 :         Unit uOut(wAUI(0));
     523           0 :         Quantity q0(wCenterOut(0), uIn);
     524           0 :         Quantity q1(wCenterOut(1), uIn);
     525           0 :         wCenterOut(0) = q0.getValue(uOut);
     526           0 :         wCenterOut(1) = q1.getValue(uOut);
     527           0 :       }
     528             : 
     529           0 :       cout << "Image pixel center " << pCenterOut << ", world center " << wCenterOut << " " << wAUI(0) << endl;
     530           0 :       dCoordFinalDir.setReferenceValue(wCenterOut);
     531             : 
     532           0 :       dCoordFinal.replaceCoordinate(dCoordFinalDir, dirCoordIndex);
     533             : 
     534             :       //PagedImage<Float> im1(nearFinalArray.shape(),dCoordFinal, "inImageReal.im");
     535             :       //im1.copyData(LatticeExpr<Float>(real(ArrayLattice<Complex>(nearFinalArray))));  
     536             :       //PagedImage<Float> im2(nearFinalArray.shape(),dCoordFinal, "inImageImag.im");
     537             :       //im2.copyData(LatticeExpr<Float>(imag(ArrayLattice<Complex>(nearFinalArray))));  
     538             : 
     539           0 :       TempImage<Float> inImage(nearFinalArray.shape(),dCoordFinal);
     540             : 
     541           0 :       TempImage<Float> tOutImage(outImage.shape(), outCS);
     542           0 :       Array<Complex> outArray(outImage.shape(), Complex(0.,0.));
     543             : 
     544           0 :       ImageRegrid<Float> iR;
     545             :       //iR.showDebugInfo(1);
     546             : 
     547           0 :       inImage.copyData(LatticeExpr<Float>(real(ArrayLattice<Complex>(nearFinalArray))));
     548           0 :       tOutImage.set(0.0);
     549             :       
     550           0 :       iR.regrid(tOutImage, Interpolate2D::LINEAR, whichOutPixelAxes, inImage); 
     551           0 :       setReal(outArray,tOutImage.get());
     552             :       
     553           0 :       inImage.copyData(LatticeExpr<Float>(imag(ArrayLattice<Complex>(nearFinalArray))));
     554           0 :       tOutImage.set(0.0);
     555             :       
     556           0 :       iR.regrid(tOutImage, Interpolate2D::LINEAR, whichOutPixelAxes, inImage);
     557           0 :       setImag(outArray,tOutImage.get());
     558             : 
     559           0 :       outImage.put(outArray);
     560             : 
     561             :       // tidy up
     562           0 :       for(uInt i=0; i<nAntTypes; i++){
     563           0 :         delete respImage_p(i);
     564             :       }
     565           0 :       respImage_p.resize(0);      
     566             : 
     567           0 :     }  
     568           0 :   }
     569             : 
     570           0 :   void ALMAAperture::applySky(ImageInterface<Float>& outImage,
     571             :                               const VisBuffer& vb, 
     572             :                               const Bool doSquint,
     573             :                               const Int& cfKey,
     574             :                               const Bool raytrace)
     575             :   {
     576           0 :     if(getVisParams(vb)==-1 || raytrace){ // need to use ray tracing
     577           0 :       ALMACalcIlluminationConvFunc almaPB;
     578           0 :       Long cachesize=(HostInfo::memoryTotal(true)/8)*1024;
     579           0 :       almaPB.setMaximumCacheSize(cachesize);
     580           0 :       almaPB.applyPB(outImage, vb, doSquint, cfKey);
     581           0 :     }
     582             :     else{ // use canned antenna responses
     583           0 :       TempImage<Complex> tI(outImage.shape(), outImage.coordinates());
     584           0 :       tI.set(Complex(0.,0.));
     585           0 :       applySky(tI, vb, doSquint, cfKey, false);
     586           0 :       outImage.put(real(abs(tI.get())));
     587           0 :     }
     588           0 :   }
     589             : 
     590           0 :   Int ALMAAperture::makePBPolnCoords(const VisBuffer&vb,
     591             :                                      const Int& convSize,
     592             :                                      const Int& convSampling,
     593             :                                      const CoordinateSystem& skyCoord,
     594             :                                      const Int& skyNx, const Int& /*skyNy*/,
     595             :                                      CoordinateSystem& feedCoord)
     596             :   {
     597           0 :     feedCoord = skyCoord;
     598             :     //
     599             :     // Make a two dimensional image to calculate auto-correlation of
     600             :     // the ideal illumination pattern. We want this on a fine grid in
     601             :     // the UV plane
     602             :     //
     603           0 :     Int directionIndex=skyCoord.findCoordinate(Coordinate::DIRECTION);
     604           0 :     AlwaysAssert(directionIndex>=0, AipsError);
     605           0 :     DirectionCoordinate dc=skyCoord.directionCoordinate(directionIndex);
     606           0 :     Vector<Double> sampling;
     607           0 :     sampling = dc.increment();
     608           0 :     sampling*=Double(convSampling);
     609           0 :     sampling*=Double(skyNx)/Double(convSize);
     610           0 :     dc.setIncrement(sampling);
     611             :     
     612             :     
     613           0 :     Vector<Double> unitVec(2);
     614           0 :     unitVec=convSize/2;
     615           0 :     dc.setReferencePixel(unitVec);
     616             :     
     617             :     // Set the reference value to that of the image
     618           0 :     feedCoord.replaceCoordinate(dc, directionIndex);
     619             : 
     620             :     //
     621             :     // Make an image with linear polarization axis.
     622             :     //
     623           0 :     Int NPol=0,M,N=0;
     624           0 :     M=polMap_p.nelements();
     625           0 :     for(Int i=0;i<M;i++){
     626           0 :       if (polMap_p(i) > -1) NPol++;
     627             :     }
     628           0 :     Vector<Int> poln(NPol);
     629             :     
     630             :     Int index;
     631           0 :     Vector<Int> inStokes;
     632           0 :     index = feedCoord.findCoordinate(Coordinate::STOKES);
     633           0 :     inStokes = feedCoord.stokesCoordinate(index).stokes();
     634           0 :     N = 0;
     635             :     try{
     636           0 :       for(Int i=0;i<M;i++) if (polMap_p(i) > -1) {poln(N) = vb.corrType()(i);N++;}
     637           0 :       StokesCoordinate polnCoord(poln);
     638           0 :       Int StokesIndex = feedCoord.findCoordinate(Coordinate::STOKES);
     639           0 :       feedCoord.replaceCoordinate(polnCoord,StokesIndex);
     640           0 :     }
     641           0 :     catch(AipsError& x){
     642           0 :       throw(SynthesisFTMachineError("Likely cause: Discrepancy between the poln. "
     643           0 :                                     "axis of the data and the image specifications."));
     644           0 :     }
     645             :     
     646           0 :     return NPol;
     647           0 :   }
     648             : 
     649             : 
     650           0 :   Vector<Int> ALMAAperture::vbRow2CFKeyMap(const VisBuffer& vb, Int& nUnique) 
     651             :   {
     652             :     // return index to outputImages for each row in vb
     653           0 :     Vector<Int> map; 
     654           0 :     map.resize(vb.nRow()); 
     655             : 
     656             :     //cout << "vb rows: " << vb.nRow() << endl;
     657             : 
     658           0 :     if(haveCannedResponses_p){
     659             :       // distinguish different antenna types
     660           0 :       if(antTypeMap_p.nelements()!=(uInt)vb.numberAnt()){
     661           0 :         antTypeMap_p.assign(antTypeMap(vb));
     662           0 :         cout << "initialising antTypeMap to " << antTypeMap_p << endl;
     663             :       }
     664             : 
     665           0 :       std::map<Int, Int > cFKeysEncountered;
     666           0 :       Int cfKeyCount = 0;
     667           0 :       for(uInt i=0; i<(uInt)vb.nRow(); i++){
     668           0 :         Int cfKey = cFKeyFromAntennaTypes(antTypeMap_p(vb.antenna1()(i)),
     669           0 :                                           antTypeMap_p(vb.antenna2()(i)));
     670           0 :         map(i) = cfKey;
     671           0 :         if(cFKeysEncountered.find(cfKey) == cFKeysEncountered.end( )){ // new cFKey
     672           0 :           cFKeysEncountered.insert(std::pair<Int, Int >(cfKey, cfKeyCount));
     673           0 :           cfKeyCount++;
     674             :         }
     675             :       }  
     676           0 :       nUnique = cfKeyCount;
     677           0 :     }
     678             :     else{ // raytracing knows only one antenna type for the moment
     679           0 :       map=0; 
     680           0 :       nUnique=1; 
     681             :     }
     682           0 :     return map;
     683           0 :   }
     684             :   
     685           0 :   Vector<ALMAAntennaType> ALMAAperture::antTypeMap(const VisBuffer& vb){
     686           0 :     Vector<ALMAAntennaType> map(vb.numberAnt(),ALMA_INVALID);
     687           0 :     for(uInt i=0; i<map.nelements(); i++){
     688           0 :       map(i) = antTypeFromName(vb.msColumns().antenna().name()(i));
     689           0 :       cout << vb.msColumns().antenna().name()(i) << " " << map(i) << endl;
     690           0 :       if(map(i)==ALMA_INVALID){
     691           0 :         logIO() << LogOrigin("ALMAAperture", "antTypeMap")
     692             :                 << LogIO::WARN 
     693             :                 << "Unrecognised antenna type for antenna \"" 
     694           0 :                 << vb.msColumns().antenna().name()(i) << "\""  
     695           0 :                 << LogIO::POST;
     696             :       }
     697             :     }
     698           0 :     return map;
     699           0 :   }
     700             : 
     701           0 :   ALMAAntennaType ALMAAperture::antTypeFromName(const String& name){
     702           0 :     ALMAAntennaType rval = ALMA_INVALID;
     703           0 :     String typeN = name.substr(0,2);
     704           0 :     if(typeN=="DV") rval=ALMA_DV;
     705           0 :     else if(typeN=="DA") rval=ALMA_DA;
     706           0 :     else if(typeN=="PM") rval=ALMA_PM;
     707           0 :     else if(typeN=="CM") rval=ALMA_CM;
     708           0 :     return rval;
     709           0 :   }
     710             : 
     711           0 :   String ALMAAperture::antTypeStrFromType(const ALMAAntennaType& aType){
     712           0 :     String tS;
     713           0 :     switch(aType){
     714           0 :     case ALMA_DV:
     715           0 :       tS = "DV";
     716           0 :       break;
     717           0 :     case ALMA_DA:
     718           0 :       tS = "DA";
     719           0 :       break;
     720           0 :     case ALMA_PM:
     721           0 :       tS = "PM";
     722           0 :       break;
     723           0 :     case ALMA_CM:
     724           0 :       tS = "CM";
     725           0 :       break;
     726           0 :     case ALMA_INVALID:
     727             :     default:
     728           0 :       tS = "UNKOWN";
     729           0 :       break;
     730             :     }
     731           0 :     return tS;
     732           0 :   }
     733             : 
     734             : 
     735           0 :   Int ALMAAperture::cFKeyFromAntennaTypes(const ALMAAntennaType aT1, const ALMAAntennaType aT2){
     736           0 :     if(orderMattersInCFKey){
     737           0 :       return (Int)aT2+1 + 10000*((Int)aT1+1); 
     738             :     }
     739             :     else{
     740           0 :       return min((Int)aT1+1, (Int)aT2+1) + 10000*max((Int)aT1+1, (Int)aT2+1); // assume order doesn't matter
     741             :     }
     742             :   }
     743             : 
     744           0 :   Vector<ALMAAntennaType> ALMAAperture::antennaTypesFromCFKey(const Int& cFKey){
     745           0 :     Int t1 = (Int) floor(cFKey/10000.);
     746           0 :     Int t2 = cFKey - 10000*t1 - 1;
     747           0 :     t1--;
     748           0 :     Vector<ALMAAntennaType> rval(1);
     749           0 :     if(t1==t2){
     750           0 :       rval(0) = (ALMAAntennaType) t1;
     751             :     }
     752             :     else{
     753           0 :       rval.resize(2);
     754           0 :       if(orderMattersInCFKey){
     755           0 :         rval(0) = (ALMAAntennaType)t1;
     756           0 :         rval(1) = (ALMAAntennaType)t2;
     757             :       }
     758             :       else{
     759           0 :         rval(0) = (ALMAAntennaType) min(t1,t2);
     760           0 :         rval(1) = (ALMAAntennaType) max(t1,t2);
     761             :       }
     762             :     }
     763           0 :     return rval;
     764           0 :   }
     765             : 
     766           0 :   Vector<ALMAAntennaType> ALMAAperture::antTypeList(const VisBuffer& vb){
     767           0 :     Vector<ALMAAntennaType> aTypeMap = antTypeMap(vb);
     768           0 :     Vector<Bool> encountered(ALMA_numAntTypes, false);
     769           0 :     uInt typeCount = 0;
     770           0 :     for(uInt i=0; i<aTypeMap.nelements(); i++){
     771           0 :       uInt index = (uInt)aTypeMap(i);
     772           0 :       if(!encountered(index)){
     773           0 :         encountered(index) = true;
     774           0 :         typeCount++;
     775             :       }
     776             :     }
     777           0 :     Vector<ALMAAntennaType> aTypeList(typeCount);
     778           0 :     uInt index = 0;
     779           0 :     for(uInt i=0; i<ALMA_numAntTypes; i++){
     780           0 :       if(encountered(i)){
     781           0 :         aTypeList(index) = (ALMAAntennaType)i;
     782           0 :         index++;
     783             :       }
     784             :     }
     785           0 :     return aTypeList;
     786           0 :   }
     787             : 
     788             : 
     789             : };

Generated by: LCOV version 1.16