LCOV - code coverage report
Current view: top level - synthesis/MeasurementComponents - UVMod.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 0 394 0.0 %
Date: 2024-10-29 13:38:20 Functions: 0 13 0.0 %

          Line data    Source code
       1             : //# UVMod.cc: Implementation of UV Modelling within calibrater
       2             : //# Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003
       3             : //# Associated Universities, Inc. Washington DC, USA.
       4             : //#
       5             : //# This library is free software; you can redistribute it and/or modify it
       6             : //# under the terms of the GNU Library General Public License as published by
       7             : //# the Free Software Foundation; either version 2 of the License, or (at your
       8             : //# option) any later version.
       9             : //#
      10             : //# This library is distributed in the hope that it will be useful, but WITHOUT
      11             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
      13             : //# License for more details.
      14             : //#
      15             : //# You should have received a copy of the GNU Library General Public License
      16             : //# along with this library; if not, write to the Free Software Foundation,
      17             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      18             : //#
      19             : //# Correspondence concerning AIPS++ should be addressed as follows:
      20             : //#        Internet email: casa-feedback@nrao.edu.
      21             : //#        Postal address: AIPS++ Project Office
      22             : //#                        National Radio Astronomy Observatory
      23             : //#                        520 Edgemont Road
      24             : //#                        Charlottesville, VA 22903-2475 USA
      25             : //#
      26             : //# $Id$
      27             : 
      28             : #include <synthesis/MeasurementComponents/UVMod.h>
      29             : 
      30             : #include <msvis/MSVis/VisibilityIterator.h>
      31             : #include <msvis/MSVis/VisSet.h>
      32             : #include <msvis/MSVis/VisBuffer.h>
      33             : #include <casacore/casa/Quanta/Quantum.h>
      34             : #include <casacore/casa/Quanta/QuantumHolder.h>
      35             : #include <casacore/measures/Measures.h>
      36             : #include <casacore/measures/Measures/MDirection.h>
      37             : #include <casacore/measures/Measures/MEpoch.h>
      38             : 
      39             : #include <casacore/casa/Arrays/ArrayMath.h>
      40             : #include <casacore/casa/Arrays/ArrayLogical.h>
      41             : #include <casacore/casa/Arrays/ArrayIter.h>
      42             : #include <casacore/scimath/Mathematics/MatrixMathLA.h>
      43             : #include <casacore/casa/BasicSL/String.h>
      44             : #include <casacore/casa/BasicMath/Math.h>
      45             : #include <casacore/casa/Utilities/Assert.h>
      46             : #include <casacore/casa/Quanta/MVTime.h>
      47             : #include <casacore/casa/Exceptions/Error.h>
      48             : #include <casacore/casa/OS/Memory.h>
      49             : #include <casacore/casa/OS/Path.h>
      50             : 
      51             : #include <components/ComponentModels/ComponentType.h>
      52             : #include <components/ComponentModels/Flux.h>
      53             : #include <components/ComponentModels/ComponentShape.h>
      54             : #include <components/ComponentModels/TwoSidedShape.h>
      55             : #include <components/ComponentModels/PointShape.h>
      56             : #include <components/ComponentModels/GaussianShape.h>
      57             : #include <components/ComponentModels/DiskShape.h>
      58             : #include <components/ComponentModels/SpectralModel.h>
      59             : #include <components/ComponentModels/ConstantSpectrum.h>
      60             : #include <components/ComponentModels/SpectralIndex.h>
      61             : #include <components/ComponentModels/SkyCompBase.h>
      62             : #include <components/ComponentModels/SkyCompRep.h>
      63             : #include <components/ComponentModels/SkyComponent.h>
      64             : #include <components/ComponentModels/ComponentList.h>
      65             : 
      66             : #include <sstream>
      67             : 
      68             : #include <casacore/casa/Logging/LogMessage.h>
      69             : #include <casacore/casa/Logging/LogSink.h>
      70             : 
      71             : 
      72             : using namespace casacore;
      73             : namespace casa { //# NAMESPACE CASA - BEGIN
      74             : 
      75             : 
      76             : // **********************************************************
      77             : //  UVMod Implementations
      78             : //
      79             : 
      80           0 : UVMod::UVMod(VisSet& vs) :
      81           0 :   vs_(NULL),
      82           0 :   cl_(NULL),
      83           0 :   svb_(NULL),
      84           0 :   fitfld_(-1),
      85           0 :   pc_(),
      86           0 :   nPar_(0),
      87           0 :   R_(),
      88           0 :   dR_(),
      89           0 :   chiSq_(0.0),
      90           0 :   lastChiSq_(0.0),
      91           0 :   sumWt_(0.0),
      92           0 :   nWt_(0),
      93           0 :   polWt_(4,false),
      94           0 :   par_(), lastPar_(),
      95           0 :   lamb_(0.001),  grad_(), lastGrad_(),
      96           0 :   hess_(), lastHess_(),
      97           0 :   dpar_(),
      98           0 :   vary_(),
      99           0 :   nVary_(0)
     100             : {
     101             :   //  cout << "UVMod ctor " << endl;
     102             : 
     103             :   // Local copy of VisSet, with correct chunking
     104           0 :   Block<Int> columns;
     105           0 :   columns.resize(4);
     106           0 :   columns[0]=MS::ARRAY_ID;
     107           0 :   columns[1]=MS::FIELD_ID;
     108           0 :   columns[2]=MS::DATA_DESC_ID;
     109           0 :   columns[3]=MS::TIME;
     110             : 
     111           0 :   vs_ = new VisSet(vs,columns,3600.0);
     112             : 
     113             :   // The VisIter/VisBuffer
     114           0 :   VisIter& vi(vs_->iter());
     115           0 :   VisBuffer vb(vi);
     116           0 :   vi.originChunks();
     117           0 :   vi.origin();
     118             : 
     119             :   // Get phase center & direction ref:
     120           0 :   pc_=vb.phaseCenter();
     121             : 
     122             :   // Check for single field (for now)
     123           0 :   fitfld()=vb.fieldId();
     124           0 :   for (vi.originChunks();
     125           0 :        vi.moreChunks();
     126           0 :        vi.nextChunk()) {
     127           0 :     vi.origin();
     128           0 :     if (vb.fieldId()!=fitfld())
     129           0 :       throw(AipsError("More than one field Id in selected data"));
     130             :   }
     131             : 
     132           0 : }
     133             : 
     134           0 : UVMod::~UVMod() {
     135             :  
     136             :   // We are only responsible for the ComponentList and VisSet
     137           0 :   if (cl_) delete cl_;  cl_=NULL;
     138           0 :   if (vs_) delete vs_;  vs_=NULL;
     139             : 
     140           0 : }
     141           0 : void UVMod::setModel(const ComponentType::Shape type, 
     142             :                      const Vector<Double> inpar,
     143             :                      const Vector<Bool> invary) {
     144             : 
     145             :   //  cout << "UVM::setModel" << endl;
     146             :   //  cout << " type = " << type << endl;
     147             :   //  cout << " inpar  = " << inpar << endl;
     148             : 
     149             :   // Create empty componentlist
     150           0 :   cl_ = new ComponentList();
     151             : 
     152           0 :   par().resize(inpar.shape());
     153           0 :   par()=inpar;
     154             : 
     155             :   // Make comp
     156           0 :   SkyComponent comp(type);
     157             : 
     158           0 :   switch (type) {
     159           0 :   case ComponentType::POINT:
     160             :     {
     161             :       // A point has 3 pars
     162           0 :       nPar()=3;
     163             : 
     164             :       // Insist par().length()=3
     165           0 :       if (inpar.nelements()!=3)  
     166           0 :         throw(AipsError("Wrong number of parameters for Point; need 3."));
     167             : 
     168           0 :       break;
     169             :     };
     170             :   
     171           0 :   case ComponentType::GAUSSIAN:
     172             :   case ComponentType::DISK:
     173             :     {
     174             : 
     175           0 :       nPar()=6;
     176             : 
     177             :       // Insist par.length()=6
     178           0 :       if (inpar.nelements()!=6)  
     179           0 :         throw(AipsError("Wrong number of parameters for resolved component; need 6."));
     180             : 
     181             :       // Convert pa to radians
     182           0 :       par()(5)*=(C::pi/180.0);
     183             :       
     184             :       // Set shape pars (all in rad)
     185           0 :       Vector<Double> gpar(3,0.0);  //  a, b, pa
     186           0 :       gpar(0)=par()(3)*(C::pi/180.0/60.0/60.0);  
     187           0 :       gpar(1)=gpar(0)*par()(4);                  
     188           0 :       gpar(2)=par()(5);
     189           0 :       comp.shape().setParameters(gpar);
     190             : 
     191           0 :       break;
     192           0 :     };
     193           0 :   default:
     194             :     {
     195           0 :       throw(AipsError("Unrecognized component type in UVMod::setModel."));
     196             :       break;
     197             :     }
     198             : 
     199             :   }
     200             : 
     201             :   // Set I
     202           0 :   comp.flux().setValue(par()(0));
     203             : 
     204             : 
     205             :   // Add to list
     206           0 :   cl().add(comp);
     207             : 
     208             : 
     209             :   // Convert direction from arcsec to radians
     210             :   //  par()(1)*=(C::pi/180.0/60.0/60.0);
     211             :   //  par()(2)*=(C::pi/180.0/60.0/60.0);
     212             : 
     213             :   // Render direction as an MDirection; use phase-center's DirRef
     214           0 :   MVDirection mvdir(par()(1)*(C::pi/180.0/60.0/60.0),par()(2)*(C::pi/180.0/60.0/60.0));
     215           0 :   MDirection dir(mvdir,pc().getRef());
     216             : 
     217             :   // Set direction in component
     218           0 :   skycomp(0).shape().setRefDirection(dir);
     219             : 
     220             :   // Handle invary flags:
     221           0 :   vary().resize(par().shape());
     222             : 
     223             :   // Assume varying everything
     224           0 :   vary()=true;
     225           0 :   nVary()=nPar();
     226             : 
     227             :   // If invary specified, set vary() accordingly
     228           0 :   for (uInt i=0; i<invary.nelements();i++)
     229           0 :     if (!invary(i)) {
     230           0 :       vary()(i) = false;
     231           0 :       nVary()-=1;
     232             :     }
     233           0 : }
     234             : 
     235           0 : Bool UVMod::modelfit(const Int& maxiter, const String file) {
     236             : 
     237             :   //  cout << "UVMod::modelfit" << endl;
     238             : 
     239             :   //  cout << " maxiter = " << maxiter << endl;
     240             :   //  cout << " file    = " << file << endl;
     241             : 
     242           0 :   LogSink logsink;
     243             : 
     244             :   // Local ref to  VisIter/VisBuffer
     245           0 :   VisIter& vi(vs().iter());
     246           0 :   VisBuffer vb(vi);
     247           0 :   svb_=&vb;
     248             : 
     249             :   // Initialize grad, hess, etc.
     250           0 :   initSolve();
     251             : 
     252             :   {
     253           0 :     LogMessage message(LogOrigin("UVMod", "solve"));
     254           0 :     ostringstream o; o<<"Solving for single-component "
     255           0 :                       << skycomp(0).shape().ident();
     256           0 :     message.message(o);
     257           0 :     logsink.post(message);
     258           0 :   }
     259             : 
     260           0 :   Int iter(0);
     261             :   // Begin solution iterations
     262             :   //  Guarantee first pass, which gets initial chi2,
     263             :   //  then evaluate convergence by chi2 comparisons
     264             : 
     265           0 :   Bool parOK(true);
     266           0 :   for (Int validiter=0;validiter<=maxiter;iter++,validiter++) {
     267             :     
     268             :     //    cout << "iter =" << iter << endl;
     269             : 
     270             :     // If we have accumulated Hess/Grad to solve, do so
     271           0 :     if (iter>0) {
     272             : 
     273             :       // If we have done at least one real solve, invoke LM
     274           0 :       if (iter > 1) {
     275           0 :         if (parOK && (chiSq()-lastChiSq()) < DBL_EPSILON) {
     276             :           // if last update succeeded
     277           0 :           lamb()*=0.5;
     278             :           //      cout << "  Good iteration, decreasing lambda: " << lamb() << "  " << validiter << endl;
     279           0 :           lastChiSq()=chiSq();
     280           0 :           lastPar()=par();      // remember these par,hess,grad,
     281           0 :           lastGrad()=grad();    //  in case we need to resolve
     282           0 :           lastHess()=hess();    //  with new lamb
     283             :         } else {
     284             :           // last update failed, so redo with new lamb
     285             :           //      validiter--;  // Don't count this iter as valid
     286           0 :           lamb()*=10.0;
     287             : 
     288             :        /*
     289             :           cout << "  Bad iteration,  increasing lambda: " << lamb();
     290             :           if (!parOK) cout << "  (bad par update)";
     291             :           else        cout << "  (chi2 increased)"; 
     292             :           cout << "  " << validiter;
     293             :           cout << endl;
     294             :        */
     295           0 :           par()=lastPar();      // recover previous par,hess,grad
     296           0 :           grad()=lastGrad();
     297           0 :           hess()=lastHess();
     298             :         }
     299             :       } else {
     300             :         // Remember first par/grad/hess
     301           0 :         lastChiSq()=chiSq();
     302           0 :         lastPar()=par();      // remember these par,hess,grad,
     303           0 :         lastGrad()=grad();    //  in case we need to resolve
     304           0 :         lastHess()=hess();    //  with new lamb
     305             :       }
     306             : 
     307             :       // Do the solve 
     308           0 :       solveGradHess();
     309           0 :       parOK=updPar();
     310             :     }
     311             : 
     312             :     // If pars are ok, calc residuals, etc.
     313           0 :     if (parOK) {
     314             :       // zero current chiSq()
     315           0 :       chiSq()=0.0;
     316           0 :       sumWt()=0.0;
     317           0 :       hess()=0.0;
     318           0 :       grad()=0.0;
     319           0 :       nWt()=0;
     320             : 
     321             :       // Loop over data to accumulate Chi2, Grad, and Hess
     322           0 :       for (vi.originChunks();
     323           0 :            vi.moreChunks();
     324           0 :            vi.nextChunk()) {
     325             :         
     326             :         // This version does not pre-apply any calibration!!
     327             :         
     328             :         // Loop over VBs:
     329           0 :         for (vi.origin();
     330           0 :              vi.more();
     331           0 :              vi++) {
     332             :           
     333             :           // Accumulate chi2 calcuation 
     334             :           //  (also accumulates residuals and differentiated residuals)
     335           0 :           chiSquare();
     336             :           
     337             :           
     338             :           // Accumulate gradients and hessian 
     339             :           //  (uses resid and diff'd resid from above)
     340           0 :           accGradHess();
     341             :           
     342             :         }
     343             :       } // chunks
     344             :       
     345             :       
     346             :       
     347             :       
     348             :       // If sum of weights is positive, we can continue with solve
     349           0 :       if (sumWt()>0) {
     350             : 
     351             :         //      chiSq()/=sumWt();
     352             :         //      cout << "chiSq(), sumWt() = " << chiSq()<< " " << sumWt() << endl;
     353             : 
     354             :         // Report chi2 and pars if a good step
     355           0 :         if ( (chiSq()-lastChiSq()) < DBL_EPSILON || iter==0) {
     356           0 :           printPar(validiter);
     357             :         }
     358             :         else {
     359           0 :           validiter--;
     360             :           //      printPar(validiter);
     361             :         }
     362             :       } else {
     363             :         // Escape and report no data!
     364           0 :         throw(AipsError("Found no data to fit!"));
     365             :       }
     366             :       
     367             :       // Don't get stuck
     368           0 :       if (iter>100) {
     369           0 :         cout << "Exceeded maximum iteration limit!" << endl;
     370           0 :         break;  
     371             :       }
     372             : 
     373             :     } 
     374             :     else
     375           0 :       validiter--;
     376             : 
     377             :   }
     378             : 
     379             :   //
     380             :   Double A; 
     381           0 :   A = chiSq()/Double(2*nWt()-nVary());
     382             :   //  grad()/=A;
     383             :   //  hess()/=A;
     384             : 
     385           0 :   lamb()=0.0;
     386           0 :   solveGradHess(true);
     387             : 
     388             :   if (false) {
     389             :   cout << "chiSq()   = " << chiSq() << endl;
     390             :   cout << "sumWt()   = " << sumWt() << endl;
     391             :   cout << "nWt()     = " << nWt() << endl;
     392             : 
     393             :   cout << "sumWt()/N = " << sumWt()/nWt() << endl;
     394             :   cout << "<chiSq()> = " << chiSq()/(sumWt()) << endl;
     395             : 
     396             :   cout << "A         = " << A  << endl;
     397             : 
     398             :   cout << "grad() = " << grad() << endl;
     399             :   //  cout << "hess() = " << hess() << endl;
     400             : 
     401             :   if (nPar()>3) {
     402             :     dpar()(5)*=(180.0/C::pi);
     403             :   }
     404             : 
     405             :   cout << "dpar() = " << dpar() << endl;
     406             : 
     407             :   cout << "cov()  = " << hess() << endl;
     408             : 
     409             :   Matrix<Double> corr;
     410             : 
     411             :   corr = hess();
     412             : 
     413             :   for (Int i=0; i<nPar(); i++) {
     414             :     for (Int j=i; j<nPar(); j++) {
     415             :       corr(i,j)/=sqrt(hess()(i,i)*hess()(j,j));
     416             :     }
     417             :   }
     418             : 
     419             :   cout << "corr    = " << corr << endl;
     420             :   }
     421             : 
     422           0 :   cout << "If data weights are arbitrarily scaled, the following formal errors" << endl
     423           0 :        << " will be underestimated by at least a factor sqrt(reduced chi2). If " << endl
     424           0 :        << " the fit is systematically poor, the errors are much worse."  << endl;
     425             : 
     426           0 :   Vector<Double> err(nPar(),0.0);
     427           0 :   for (Int ipar=0; ipar<nPar(); ipar++) 
     428           0 :     if (vary()(ipar))
     429           0 :       err(ipar)=sqrt(hess()(ipar,ipar));
     430             :   
     431             :   
     432           0 :   cout << "I = " << par()(0) << " +/- " << err(0) << endl;
     433           0 :   cout << "x = " << par()(1) << " +/- " << err(1) << " arcsec" << endl;
     434           0 :   cout << "y = " << par()(2) << " +/- " << err(2) << " arcsec" << endl;
     435           0 :   if (nPar()>3) {
     436           0 :     cout << "a = " << par()(3) << " +/- " << err(3) << " arcsec" << endl;
     437           0 :     cout << "r = " << par()(4) << " +/- " << err(4) << endl;
     438           0 :     cout << "p = " << par()(5)*180.0/C::pi << " +/- " << err(5)*180.0/C::pi << " deg" << endl;
     439             :   }
     440             : 
     441             :   //  }  // (false)
     442             : 
     443             :   // Shift pa back to deg
     444           0 :   if (par().nelements()>3) {
     445           0 :     par()(5)*=(180.0/C::pi);
     446             :   }
     447             : 
     448             :   // Shift model to phase center of selected field
     449           0 :   MDirection newdir;
     450           0 :   newdir=pc();
     451           0 :   newdir.shift(skycomp(0).shape().refDirection().getValue(),true);
     452           0 :   skycomp(0).shape().setRefDirection(newdir);
     453             : 
     454             :   // Export componentlist to file, if specified
     455           0 :   if (file.length()>0) {
     456           0 :     Path path(file);
     457           0 :     cout << "Writing componentlist to file: "
     458           0 :          << path.absoluteName()
     459           0 :          << endl;
     460           0 :     cl().rename(path);
     461           0 :   }
     462             : 
     463           0 :   return true;
     464             : 
     465           0 : }
     466             : 
     467           0 : void UVMod::initSolve() {
     468             : 
     469             :   //  cout << "UVM::initSolve" << endl;
     470             : 
     471             :   // Chi2 and weights
     472           0 :   chiSq()=0.0;
     473           0 :   sumWt()=0.0;
     474           0 :   nWt()=0;
     475             : 
     476           0 :   lastPar().resize(nPar());
     477             : 
     478             :   // Gradient and Hessian
     479           0 :   grad().resize(nPar());
     480           0 :   grad()=0.0;
     481             : 
     482           0 :   lastGrad().resize(nPar());
     483           0 :   lastGrad()=0.0;
     484             : 
     485           0 :   hess().resize(nPar(),nPar()); 
     486           0 :   hess()=0.0;
     487             : 
     488           0 :   lastHess().resize(nPar(),nPar()); 
     489           0 :   lastHess()=0.0;
     490             : 
     491           0 :   dpar().resize(nPar());
     492           0 :   dpar()=0.0;
     493             : 
     494           0 :   lamb()=0.001;
     495             : 
     496           0 : }
     497             : 
     498           0 : void UVMod::chiSquare() {
     499             : 
     500             :   //  cout << "UVM::chiSquare" << endl;
     501             : 
     502             :   // Get residuals w.r.t. current parameters
     503           0 :   residual();
     504             : 
     505             :   // Pointer access to vb elements
     506           0 :   const Bool*  flr=&svb().flagRow()(0);
     507           0 :   const Bool*  fl= &svb().flag()(0,0);
     508           0 :   const Int*   a1= &svb().antenna1()(0);
     509           0 :   const Int*   a2= &svb().antenna2()(0);
     510           0 :   const Float* wt= &svb().weight()(0);
     511             : 
     512             : 
     513           0 :   Int nCorr = R().shape()(0);
     514             : 
     515             :   DComplex* res;
     516             : 
     517             :   // Loop over row/channel
     518           0 :   Int irow(0),ich(0),icorr(0);
     519           0 :   for (irow=0;irow<svb().nRow();irow++,flr++,a1++,a2++,wt++) {
     520           0 :     if (!(*flr) && (*a1)!=(*a2)) { // not flagrow nor AC
     521           0 :       fl=&svb().flag()(0,irow);
     522           0 :       for (ich=0;ich<svb().nChannel();ich++,fl++) {
     523           0 :         if (!(*fl)) {
     524             : 
     525           0 :           res=&R()(0,ich,irow);
     526           0 :           for (icorr=0; icorr<nCorr; icorr++,res++) {
     527             : 
     528           0 :             if ( polWt()(icorr) ) {
     529           0 :               chiSq() += Double(*wt)*real((*res)*conj(*res));
     530           0 :               sumWt() += Double(*wt);
     531           0 :               nWt()   += 1;
     532             : 
     533             :             /*
     534             :               cout << irow << " " << *a1 << " " << *a2 << " ";
     535             :               cout << "*res = " << *res << " ";
     536             :               cout << innerProduct((*res),(*res)) << " ";
     537             :               cout << chiSq()/sumWt();
     538             :               cout << endl;
     539             :             */
     540             : 
     541             :           //      chiSq() += real(innerProduct((*res),(*res)));
     542             :           //      sumWt() += 1.0;
     543             :             }
     544             :           }
     545             : 
     546             :         }
     547             :       }
     548             :     }
     549             :   }
     550             : 
     551             :   //  cout << "End of UVM::chiSquare" << chiSq() << endl;
     552             : 
     553           0 : }
     554             : 
     555             :   
     556             : //  Vobs - (M)*Vmod,  - (dM)*Vmod
     557           0 : void UVMod::residual() {  
     558             : 
     559             :   //  cout << "UVM::residual" << endl;
     560             : 
     561             :   // Shapes
     562           0 :   Int nRow= svb().nRow();
     563           0 :   Int nChan=svb().nChannel();
     564             : 
     565             :   // Data Access
     566           0 :   const Bool*    flagR= &svb().flagRow()(0);
     567           0 :   const Bool*    flag=  &svb().flag()(0,0);
     568           0 :   const Int*     a1= &svb().antenna1()(0);
     569           0 :   const Int*     a2= &svb().antenna2()(0);
     570           0 :   const RigidVector<Double,3>* uvw = &svb().uvw()(0);
     571             : 
     572             :   // Prepare residuals array
     573           0 :   Int nCorr = svb().correctedVisCube().shape()(0);
     574           0 :   R().resize(nCorr,nChan,nRow);
     575           0 :   convertArray(R(),svb().correctedVisCube());
     576             : 
     577             :   // Zero cross-hands...
     578             :   //  TBD
     579             : 
     580             :   // Prepare differentials array
     581           0 :   dR().resize(IPosition(4,nCorr,nPar(),nChan,nRow));
     582           0 :   dR()=DComplex(0.0);
     583             : 
     584             :   // Calculate wave number per frequency
     585           0 :   Vector<Double> freq = svb().frequency();
     586           0 :   Vector<Double> waveNum = C::_2pi*freq/C::c;
     587             : 
     588             :   //  cout << "waveNum = " << waveNum << endl;
     589             : 
     590             :   //  cout << "Polarizations = " << svb().corrType() << endl;
     591             : 
     592             : 
     593           0 :   Vector<Int> corridx = svb().corrType();
     594             : 
     595             :   // Ensure component is in correct pol
     596           0 :   ComponentType::Polarisation pol(ComponentType::CIRCULAR);
     597           0 :   if (svb().polFrame()==0) {
     598           0 :     pol=ComponentType::CIRCULAR;
     599           0 :     corridx-=5;
     600             :   }
     601           0 :   else if (svb().polFrame()==1) {
     602           0 :     pol=ComponentType::LINEAR;
     603           0 :     corridx-=9;
     604             :   }
     605             : 
     606             :   // Handle polarization selections (parallel hands only, for now)
     607           0 :   polWt().resize(nCorr);
     608           0 :   polWt()=false;
     609           0 :   polWt() = (corridx==0 || corridx==3);
     610             : 
     611           0 :   skycomp(0).flux().convertPol(pol);
     612             : 
     613             :   // The per-row model visibility
     614           0 :   Vector<DComplex> M(4);  
     615             : 
     616             :   // The comp flux
     617           0 :   Vector<DComplex> F(4);
     618           0 :   F = skycomp(0).flux().value();
     619             : 
     620             :   // The Direction visibility, derivatives
     621           0 :   DComplex D, dphdx, dphdy;
     622             : 
     623             :   // short-hand access to pars
     624           0 :   Vector<Double> p;
     625           0 :   p.reference(par());
     626             : 
     627             :   // Utility
     628           0 :   Vector<DComplex> dMdG;
     629             :   Double cospa;
     630             :   Double sinpa;
     631           0 :   Double dGda(0.0), G(0.0), g1(0.0),g2(0.0);
     632           0 :   Double pi2a2(0.0);
     633           0 :   if (nPar()>3)
     634           0 :     pi2a2=C::pi*C::pi*p(3)*p(3);
     635             :             
     636             :   // Pointer access to R(), dR();
     637           0 :   DComplex  *res = &R()(0,0,0);
     638           0 :   DComplex *dres = &dR()(IPosition(4,0,0,0,0));
     639             : 
     640             :   // iterate rows
     641           0 :   for (Int row=0; row<nRow; row++,flagR++,uvw++,a1++,a2++) {
     642             : 
     643           0 :     if (!*flagR && (*a1)!=(*a2)) { // not flagrow nor AC
     644             : 
     645           0 :       flag = &svb().flag()(0,row);
     646           0 :       for (Int chn=0; chn<nChan; chn++,flag++) {
     647             :         
     648             :         // if this data channel unflagged
     649           0 :         if (!*flag) {
     650             : 
     651           0 :           Vector<Double> uvw2(uvw->vector());
     652             :           // The model visbility vector
     653           0 :           M=skycomp(0).visibility(uvw2,freq(chn)).value();
     654             : 
     655             :           // Scale uvw2 to 1/arcsec (dir pars are in arcsec)
     656           0 :           uvw2/=(648000/C::pi);
     657             : 
     658             :           // Direction phase factors (OPTIMIZED?)
     659           0 :           Double phase=waveNum(chn)*( uvw2(0)*p(1)+uvw2(1)*p(2) );
     660           0 :           D=DComplex(cos(phase),sin(phase));
     661           0 :           dphdx=DComplex(0.0,uvw2(0)*waveNum(chn));
     662           0 :           dphdy=DComplex(0.0,uvw2(1)*waveNum(chn));
     663             : 
     664             :           // apply direction phase
     665           0 :           M*=D;  
     666             : 
     667             :           // Resolved component geometry derivatives
     668           0 :           if (nPar()>3) {
     669             :             
     670           0 :             cospa=cos(p(5));
     671           0 :             sinpa=sin(p(5));
     672           0 :             g1=waveNum(chn)*(uvw2(0)*cospa - uvw2(1)*sinpa)/C::_2pi;
     673           0 :             g2=waveNum(chn)*(uvw2(0)*sinpa + uvw2(1)*cospa)/C::_2pi;
     674           0 :             dGda=C::pi*sqrt(g1*g1*p(4)*p(4) + g2*g2);
     675           0 :             G=p(3)*dGda;
     676             :             
     677             :             // Gaussian-specific, for now
     678           0 :             switch (skycomp(0).shape().type()) {
     679           0 :             case ComponentType::GAUSSIAN:
     680             :               {
     681           0 :                 dMdG=M*DComplex(-G/2.0/C::ln2);
     682           0 :                 break;
     683             :               }
     684           0 :             case ComponentType::DISK:
     685             :               {
     686           0 :                 dMdG=M*DComplex(-2.0*jn(2,G)/G);
     687           0 :                 break;
     688             :               }
     689           0 :             default:
     690             :               {
     691           0 :                 break;
     692             :               }
     693             :             }
     694             :           }
     695             : 
     696             :           // Fill R, dR by element:
     697           0 :           res  = &R()(0,chn,row);
     698           0 :           dres = &dR()(IPosition(4,0,0,chn,row));
     699           0 :           Int cidx(0);
     700           0 :           for (Int icorr=0; icorr<nCorr; icorr++,res++,dres++) {
     701             : 
     702           0 :             if (polWt()(icorr)) {
     703             : 
     704             :               // Re-index correlations in model
     705             :               //  (copes with partial or mis-ordered data correlations)
     706           0 :               cidx=corridx(icorr);
     707             :               
     708             :               // The residual itself
     709           0 :               *(res) -= M(cidx);
     710             :               
     711             :               // Flux derivative
     712           0 :               *(dres) = -M(cidx)/F(cidx);
     713             :               
     714             :               // Direction derivatives
     715           0 :               *(dres+1*nCorr) = -M(cidx)*dphdx;
     716           0 :               *(dres+2*nCorr) = -M(cidx)*dphdy;
     717             :               
     718             :               // If fitting resolved shapes:
     719           0 :               if (nPar()>3) {
     720             :                 
     721             :                 // 2D-comp-specific par derivatives
     722             :                 
     723             :                 // a
     724           0 :                 *(dres+3*nCorr) = -dMdG(cidx)*dGda;
     725             :                 
     726             :                 // r = b/a
     727           0 :                 *(dres+4*nCorr) = -dMdG(cidx)*(pi2a2*p(4)*g1*g1/G);
     728             :                 
     729             :                 // pa
     730           0 :                 *(dres+5*nCorr) = -dMdG(cidx)*(pi2a2*(1.0-p(4)*p(4))*g1*g2/G);
     731             :               }
     732             :             }
     733             :           }         
     734           0 :         } // !*flag
     735             :       } // chn
     736             :     } // !*flagR
     737             :   } // row
     738             : 
     739             :   //  cout << "End of UVM::residual" << endl;
     740             : 
     741             : 
     742           0 : }
     743             : 
     744           0 : void UVMod::accGradHess() {
     745             : 
     746             :   // Assumes we've already calculated R() & dR()  (via chiSquare/residual)
     747             : 
     748             :   //  cout << "UVM::accGradHess" << endl;
     749             :   
     750           0 :   const Bool*  flagR= &svb().flagRow()(0);
     751           0 :   const Bool*  flag=  &svb().flag()(0,0);
     752           0 :   const Int*   a1=    &svb().antenna1()(0);
     753           0 :   const Int*   a2=    &svb().antenna2()(0);
     754           0 :   const Float* wt=    &svb().weight()(0);
     755             : 
     756           0 :   Int nCorr = R().shape()(0);
     757             : 
     758             :   DComplex *res;
     759             :   DComplex *dres1, *dres2;
     760             : 
     761             :   //  grad()=0.0;
     762             :   //  hess()=0.0;
     763             : 
     764             :   //  cout << endl;
     765             : 
     766           0 :   for (Int irow=0;irow<svb().nRow();irow++,a1++,a2++,flagR++,wt++) {
     767             :    
     768           0 :     if (!(*flagR)) {
     769             : 
     770           0 :       flag=  &svb().flag()(0,irow);
     771           0 :       for (Int ich=0;ich<svb().nChannel();ich++,flag++) {
     772             :         
     773           0 :         if (!(*flag)) {
     774             :           
     775           0 :           res = &R()(0,ich,irow);
     776           0 :           for (Int icorr=0; icorr<nCorr; icorr++,res++) {
     777             :                 
     778           0 :             if ( polWt()(icorr) ) {
     779           0 :               dres1 = &dR()(IPosition(4,icorr,0,ich,irow));
     780           0 :               for (Int ipar0=0;ipar0<nPar();ipar0++,dres1+=nCorr) {
     781             :                 
     782             :                 // Only if this parameter varies, calc grad/hess
     783           0 :                 if (vary()(ipar0)) {
     784           0 :                   grad()(ipar0)       += (Double(*wt)*real( (*res)   * conj(*dres1) ) );
     785           0 :                   hess()(ipar0,ipar0) += (Double(*wt)*real( (*dres1) * conj(*dres1) ) );
     786             : 
     787           0 :                   dres2 = dres1+nCorr;
     788           0 :                   for (Int ipar1=ipar0+1;ipar1<nPar();ipar1++,dres2+=nCorr) {
     789           0 :                     if (vary()(ipar1))
     790           0 :                       hess()(ipar0,ipar1) += (Double(*wt)*real( (*dres1) * conj(*dres2) ) );
     791             :                   }
     792             :                 }
     793             :               }
     794             :             }
     795             :           }
     796             :         }
     797             : 
     798             :       }
     799             :     }
     800             :   }
     801             : 
     802             :   //  cout << "grad() = " << grad().column(1) << endl;
     803             :   //  cout << "hess() = " << hess().xyPlane(1) << endl;
     804             : 
     805             : 
     806             : 
     807           0 : }
     808             : 
     809           0 : void UVMod::solveGradHess(const Bool& doCovar) {
     810             : 
     811             :   //  cout << "UVM::solveGradHess" << endl;
     812             : 
     813             :   // Treat diagonal
     814           0 :   for (Int ipar=0; ipar<nPar(); ipar++) {
     815             :     // Ensure non-zero diag
     816           0 :     if (hess()(ipar,ipar)==0.0)   // corresponds to vary()(ipar)=false
     817           0 :       hess()(ipar,ipar)=1.0;
     818             : 
     819             :     // apply lamb() to diag (if covar matrix not requested)
     820           0 :     if (!doCovar) hess()(ipar,ipar)*=(1.0+lamb());
     821             :   }
     822             : 
     823             :   //  cout << "grad() = " << grad() << endl;
     824             :   //  cout << "hess() = " << hess() << endl;
     825             : 
     826             : 
     827           0 :   char uplo('U');
     828           0 :   Int n(nPar());
     829           0 :   Int nrhs(1);
     830             :   Bool deleteaa, deletebb;
     831           0 :   Int lda(n);
     832           0 :   Int ldb(n);
     833             :   Int info;
     834             :   Double *aa;
     835             :   Double *bb;
     836             :     
     837           0 :   if (sumWt() > 0.0) {
     838             :     
     839           0 :     aa = hess().getStorage(deleteaa);
     840           0 :     bb = grad().getStorage(deletebb);
     841             :     
     842           0 :     posv(&uplo, &n, &nrhs, aa, &lda, bb, &ldb, &info);
     843             : 
     844           0 :     if (doCovar) potri(&uplo, &n, aa, &lda, &info);
     845             : 
     846             :     //      if (info!=0) cout << "info = " << info << endl;
     847             :     
     848           0 :     hess().putStorage(aa,deleteaa);
     849           0 :     grad().putStorage(bb,deletebb);
     850             :   }
     851           0 :   dpar()=grad();
     852             : 
     853             :   //  cout << "dpar() = " << dpar() << endl;
     854             : 
     855           0 : }
     856             : 
     857           0 : Bool UVMod::updPar() {
     858             : 
     859             :   //  cout << "UVM::updPar" << endl;
     860             : 
     861             :   //  cout << endl << "dpar() = " << dpar() << endl;
     862             : 
     863             : 
     864             :   // Handle "unphysical" updates:
     865             : 
     866           0 :   if (nPar() > 3 ) {
     867           0 :     if (dpar()(3) > par()(3))   // Keep size positive
     868           0 :       dpar()(3) = 0.9*par()(3);
     869           0 :     if (dpar()(4) > par()(4))   // Keep axial ratio positive
     870           0 :       dpar()(4) = 0.9*par()(4);
     871             :   }
     872             : 
     873             :   // Update pars 
     874           0 :   par()-=dpar();
     875             : 
     876           0 :   if (nPar()>3 && par()(4) > 1.0) par()(4)=1.0;  // Keep axial ration <= 1
     877             : 
     878             : 
     879             :   // Set current pars in the componentlist
     880           0 :   return setCompPar();
     881             : 
     882             : }
     883             : 
     884           0 : Bool UVMod::setCompPar() {
     885             : 
     886             :   // Update I flux:
     887           0 :   skycomp(0).flux().convertPol(ComponentType::STOKES);
     888           0 :   skycomp(0).flux().setValue(par()(0));
     889             : 
     890           0 :   Double rad2as(180.0*60.0*60.0/C::pi);
     891             : 
     892             :   // Update (relative) direction:
     893           0 :   MVDirection mvdir(par()(1)/rad2as,par()(2)/rad2as);
     894           0 :   MDirection dir(mvdir);
     895           0 :   skycomp(0).shape().setRefDirection(dir);
     896             : 
     897             :   // Set shape pars
     898           0 :   if (skycomp(0).shape().nParameters() > 0) {
     899             : 
     900             :     // Keep pa within a quarter cycle of zero
     901           0 :     while (par()(5) > C::pi/2.0)  par()(5)-=C::pi;
     902           0 :     while (par()(5) < -C::pi/2.0) par()(5)+=C::pi;
     903             :     
     904           0 :     Vector<Double> gpar(skycomp(0).shape().parameters());  //  a, b, pa
     905             :     //    cout << "gpar = " << gpar << endl;
     906           0 :     gpar(0)=par()(3)/rad2as;   // a (rad)
     907           0 :     gpar(1)=gpar(0)*par()(4);  // b = a*r (rad)
     908           0 :     gpar(2)=par()(5);          // pa (rad)
     909             : 
     910             : 
     911             :     // Now set new pars
     912             :     //    cout << "gpar = " << gpar << endl;
     913             :     try {
     914           0 :       skycomp(0).shape().setParameters(gpar);
     915           0 :     } catch (AipsError& x) {
     916           0 :       cout << " This should never happen now:  " << x.getMesg() << endl;
     917           0 :       return false;
     918           0 :     }
     919           0 :   }
     920           0 :   return true;
     921           0 : }
     922             : 
     923           0 : void UVMod::printPar(const Int& iter) {
     924             : 
     925             :   //  cout << "UVM::printPar" << endl;
     926             :   
     927             :   // Ensure component is in Stokes:
     928           0 :   skycomp(0).flux().convertPol(ComponentType::STOKES);
     929             : 
     930             :   // Extract flux:
     931           0 :   Vector<Double> f;
     932           0 :   skycomp(0).flux().value(f);
     933             : 
     934           0 :   if (iter==0) {
     935           0 :     cout << "There are " 
     936           0 :          << 2*nWt() << " - " 
     937           0 :          << nVary() << " = " 
     938           0 :          << 2*nWt()-nVary() << " degrees of freedom." 
     939           0 :          << endl;
     940             :   }
     941             : 
     942           0 :   cout << " iter=" << iter << ":  ";
     943             : 
     944             :   //  cout << " lastchi2=" << lastChiSq() << " ";
     945             : 
     946           0 :   if (iter>0 && (chiSq()-lastChiSq())>DBL_EPSILON ) cout << "(";
     947           0 :   cout << " reduced chi2=" << chiSq()/Double(2*nWt()-nVary());
     948           0 :   if (iter>0 && (chiSq()-lastChiSq())>DBL_EPSILON ) cout << ")";
     949             : 
     950             :   //  cout << "(" << lamb() << ")";
     951             : 
     952           0 :   cout << ":  I=" <<  f(0)
     953           0 :        << ",  dir=" 
     954           0 :        << skycomp(0).shape().refDirection().getAngle(Unit("arcsec"));
     955             : 
     956           0 :   if (skycomp(0).shape().nParameters()>0) {
     957           0 :     Vector<Double> gpar(skycomp(0).shape().parameters());  //  a, b, pa
     958           0 :     cout << ",  shape=["
     959           0 :          << gpar(0)*180.0*60.0*60.0/C::pi << ", "   // a (arcsec)
     960           0 :          << gpar(1)/gpar(0) << ", "                 // r
     961           0 :          << gpar(2)*180.0/C::pi << "]";             // pa (deg)
     962           0 :   }
     963           0 :   cout << endl;
     964             :     
     965           0 : }
     966             : 
     967             : } //# NAMESPACE CASA - END
     968             : 

Generated by: LCOV version 1.16