Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

pixel_amp_array.h

Go to the documentation of this file.
00001 /*
00002 Arroyo - software for the simulation of electromagnetic wave propagation
00003 through turbulence and optics.
00004 
00005 Copyright (c) 2000-2004 California Institute of Technology.  Written by
00006 Dr. Matthew Britton.  For comments or questions about this software,
00007 please contact the author at mbritton@astro.caltech.edu.
00008 
00009 This program is free software; you can redistribute it and/or modify it
00010 under the terms of the GNU General Public License as  published by the
00011 Free Software Foundation; either version 2 of the License, or (at your
00012 option) any later version.
00013 
00014 This program is provided "as is" and distributed in the hope that it
00015 will be useful, but WITHOUT ANY WARRANTY; without even the implied
00016 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  In no
00017 event shall California Institute of Technology be liable to any party
00018 for direct, indirect, special, incidental or consequential damages,
00019 including lost profits, arising out of the use of this software and its
00020 documentation, even if the California Institute of Technology has been
00021 advised of the possibility of such damage.   The California Institute of
00022 Technology has no obligation to provide maintenance, support, updates,
00023 enhancements or modifications.  See the GNU General Public License for
00024 more details.
00025 
00026 You should have received a copy of the GNU General Public License along
00027 with this program; if not, write to the Free Software
00028 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00029 */
00030 
00031 #ifndef PIXEL_AMP_ARRAY_H
00032 #define PIXEL_AMP_ARRAY_H
00033 
00034 #include <vector>
00035 #include <algorithm>
00036 #include <iomanip>
00037 #include <cmath>
00038 #include "linear_algebra.h"
00039 #include "fft_manager.h"
00040 #include "pixel_array.h"
00041 
00042 namespace Arroyo {
00043 
00044   using std::string;
00045   using std::vector;
00046   using std::ostream;
00047 
00048   /* forward declarations */
00049   template <class precision> class pixel_amp_array;
00050   template <class precision> bool operator == (const pixel_amp_array<precision> &p1,
00051                                         const pixel_amp_array<precision> &p2);
00052   template <class precision> bool operator != (const pixel_amp_array<precision> &p1,
00053                                         const pixel_amp_array<precision> &p2);
00054 
00059 
00060   template <class precision>
00061     class pixel_amp_array :
00062     public pixel_array<precision> {
00063 
00064     public:
00065 
00068     pixel_amp_array() : pixel_array<precision>() {};
00069 
00072     template<class U>
00073       pixel_amp_array(const pixel_amp_array<U> & pixamparr){
00074       pixel_amp_array::operator=(pixamparr);
00075     };
00076 
00079     template<class U>
00080       pixel_amp_array(const pixel_array<U> & pixarr){
00081       pixel_array<precision>::operator=(pixarr);
00082     };
00083 
00086     pixel_amp_array(const iofits & iof) : pixel_array<precision>(iof) {};
00087 
00090     pixel_amp_array(const std::vector<long> & in_axes, 
00091                     const precision * data = NULL, 
00092                     const float * wts = NULL) :
00093       pixel_array<precision>(in_axes, data, wts) {};
00094 
00098     template<class U>
00099       pixel_amp_array(const pixel_amp_array<U> & pixarr,
00100                         const std::vector<long> & pixel_limits) 
00101         : pixel_array<precision>(pixarr, pixel_limits) {};
00102 
00105     template <class U>
00106       pixel_amp_array(std::vector<pixel_amp_array<U> *> & paas);
00107 
00110     ~pixel_amp_array(){};  
00111 
00114     pixel_amp_array & operator = (const pixel_amp_array<precision> & pixamparr){
00115       if(this == &pixamparr)
00116         return(*this);
00117       pixel_array<precision>::operator=(pixamparr);
00118       return(*this);
00119     };
00120 
00126     void mean_and_rms(double & mean, double & rms) const;
00127 
00131     void sigma_clip(const int & niter, const double & sigma_clip);
00132 
00135     void amp_clip(const double & min, const double & max);
00136 
00141     void interpolate();
00142     
00152     double fit(const pixel_amp_array<precision> & psf, 
00153                double & differential_amplitude,
00154                vector<double> & relative_offsets,
00155                pixel_amp_array<precision> & fitted_psf,
00156                pixel_amp_array<precision> & fit_residual,
00157                pixel_amp_array<precision> & orig) const;
00158 
00167     double fit(const pixel_amp_array<precision> & psf, 
00168                double & differential_amplitude,
00169                double & offset,
00170                bool fit_for_offset,
00171                vector<double> & relative_offsets,
00172                pixel_amp_array<precision> & fitted_psf,
00173                pixel_amp_array<precision> & fit_residual,
00174                pixel_amp_array<precision> & orig) const;
00175 
00185     double fit(int npsfs,
00186                const pixel_amp_array<precision> & psf, 
00187                vector<double> & differential_amplitudes,
00188                vector<vector<double> > & relative_offsets,
00189                pixel_amp_array<precision> & fitted_model,
00190                pixel_amp_array<precision> & fit_residual) const;
00191 
00195     double aperture_photometry(double x, double y, double inner_radius,
00196                                                 double outer_radius) const;
00197 
00203     template<class U>
00204       void flag_outliers(const pixel_amp_array<U> & pixamparr,
00205                                                 const double & threshold);
00206 
00209     std::vector<float> azav(int xcenter, int ycenter);
00210 
00213     friend bool operator ==(const pixel_amp_array<precision> &p1,
00214                                 const pixel_amp_array<precision> &p2) {
00215       if(p1.get_axes()!=p2.get_axes()) return(0);
00216       for(int i=0; i<p1.axes.size(); i++)
00217         for(int j=0; j<p1.axes[i]; j++)
00218           if(p1.pixeldata[i]!=p2.pixeldata[i]) return(0);
00219     
00220       if((p1.pixelwts!=NULL && p2.pixelwts==NULL) ||
00221          (p1.pixelwts==NULL && p2.pixelwts!=NULL)){
00222         cerr << "pixel_amp_array<precision> & operator == error - "
00223              << "weights not defined for both objects\n";
00224         throw(std::string("pixel_amp_array<precision> & operator =="));
00225       }
00226     
00227       if(p1.pixelwts!=NULL)
00228         for(int i=0; i<p1.axes.size(); i++)
00229           for(int j=0; j<p1.axes[i]; j++)
00230             if(p1.pixelwts[i]!=p2.pixelwts[i]) return(0);
00231     
00232       return(1);
00233     };
00234   };  
00235 
00236 
00237   template<class precision>
00238     template <class U>
00239     pixel_amp_array<precision>::pixel_amp_array(std::vector<pixel_amp_array<U> *> & paas){
00240   
00241     if(pixel_array<precision>::verbose_level) 
00242       cout << "pixel_amp_array::pixel_amp_array - forming array from median of " 
00243            << paas.size() << " images\n";
00244   
00245     if(paas.size()==0){
00246       pixel_amp_array<U> pixarr;
00247       operator=(pixarr);
00248       return;
00249     }
00250     if(paas.size()==1 || paas.size()==2){
00251       operator=(*(paas[0]));
00252       return;
00253     }
00254   
00255     for(int i=0; i<paas.size(); i++){
00256       if(paas[i]->axes!=paas[0]->axes){
00257         cerr << "pixel_amp_array::pixel_amp_array error - "
00258              << "pixel_amp_arrays have mismatched axes\n";  
00259         paas[i]->print_axes(cerr);
00260         paas[0]->print_axes(cerr);
00261         throw(std::string("pixel_amp_array::pixel_amp_array"));
00262       }
00263     }    
00264   
00265     int narrays = paas.size();
00266     int medelem = narrays/2;
00267     int nelem = paas[0]->total_space();
00268     std::vector<U> array(paas.size());
00269     pixel_array<precision> pa(paas[0]->axes, NULL, NULL);
00270     pixel_array<precision>::operator=(pa);
00271     for(int i=0; i<nelem; i++){
00272       for(int j=0; j<narrays; j++)
00273         array[j] = (precision)(paas[j]->data(i));
00274       sort(array.begin(),array.end());
00275       pixel_array<precision>::pixeldata[i] = array[medelem];
00276     }
00277   }
00278 
00279   template<class precision>
00280     void pixel_amp_array<precision>::mean_and_rms(double & mean, double & rms) const {
00281   
00282     int nelems = pixel_array<precision>::total_space();
00283     if(nelems < 2){
00284       cerr << "pixel_amp_array<precision>::mean_and_rms error - "
00285            << "cannot compute rms with less than 2 points\n";
00286       throw(std::string("pixel_amp_array<precision>::mean_and_rms"));
00287     }
00288   
00289     mean = 0;
00290     double meansq = 0, wts = 0;
00291     if(pixel_array<precision>::pixelwts==NULL){
00292       for(int i=0; i<nelems; i++)
00293         mean += pixel_array<precision>::pixeldata[i];
00294       mean = mean/((double)nelems);
00295       for(int i=0; i<nelems; i++)
00296         meansq += pixel_array<precision>::pixeldata[i]*pixel_array<precision>::pixeldata[i] - mean*mean;
00297       meansq = meansq/((double)(nelems));
00298     } else {
00299       for(int i=0; i<nelems; i++){
00300         mean += pixel_array<precision>::pixeldata[i]*pixel_array<precision>::pixelwts[i];
00301         wts += pixel_array<precision>::pixelwts[i];
00302       }
00303       if(wts==0){
00304         cerr << "pixel_amp_array<precision>::mean_and_rms error - weights are all zero\n";
00305         throw(std::string("pixel_amp_array<precision>::mean_and_rms"));
00306       }
00307       mean /= wts;
00308       for(int i=0; i<nelems; i++)
00309         meansq += (pixel_array<precision>::pixeldata[i] - mean)*(pixel_array<precision>::pixeldata[i]-mean)*pixel_array<precision>::pixelwts[i];
00310       meansq /= wts;
00311     }
00312   
00313     if(meansq<0){
00314       cerr << "pixel_amp_array<precision>::mean_and_rms error - mean square < 0\n";
00315       cerr << "mean " << mean << "\twts " << wts << "\tmeansq " << meansq << endl;
00316       throw(std::string("pixel_amp_array<precision>::mean_and_rms"));
00317     }
00318   
00319     if(pixel_array<precision>::verbose_level)
00320       cerr << "pixel_amp_array<precision>::mean_and_rms - returning meansq "
00321            << meansq << " mean " 
00322            << mean << "\trms " << sqrt(meansq) << endl;
00323     rms = sqrt(meansq);
00324   }
00325 
00326   template<class precision>
00327     void pixel_amp_array<precision>::sigma_clip(const int & niter,
00328                                         const double & sigma_clip){
00329 
00330     if(pixel_array<precision>::pixelwts==NULL) pixel_array<precision>::allocate_weights(1);
00331   
00332     int bad_pixel_count = 0;
00333     double mean, rms=0, last_rms=-1, wtsq;
00334     int nelem = this->total_space();
00335   
00336     for(int i=0; i<niter; i++){
00337       mean_and_rms(mean, rms);
00338       if(rms == 0)
00339         cout << "pixel_amp_array<precision>::sigma_clip warning:"
00340              << " rms = 0 - setting all weights to zero\n";
00341       if(pixel_array<precision>::verbose_level) 
00342         cout << "pixel_amp_array<precision>::sigma_clip - "
00343              << "clipping all points with value less than " 
00344              << mean + sigma_clip*rms << endl;
00345 
00346       if(last_rms==rms) break;
00347 
00348       for(int i=0; i<nelem; i++){
00349         if(pixel_array<precision>::pixelwts[i]!=0 && fabs(pixel_array<precision>::pixeldata[i]-mean) > sigma_clip*rms){
00350           pixel_array<precision>::pixeldata[i] = 0;
00351           pixel_array<precision>::pixelwts[i] = 0;
00352           bad_pixel_count++;
00353         }
00354       }
00355       last_rms = rms;
00356     }
00357     if(pixel_array<precision>::verbose_level) {
00358       cerr << "pixel_amp_array<precision>::sigma_clip - clipped " 
00359            << bad_pixel_count << " out of " << this->total_space() << " points ("
00360            << ((double)(bad_pixel_count)/((double)this->total_space()*100.0)) << "%)\n";
00361       cerr << "pixel_amp_array<precision>::sigma_clip - mean " << mean
00362            << "\trms " << rms << endl;
00363     }
00364   }
00365 
00366   template<class precision>
00367     void pixel_amp_array<precision>::amp_clip(const double & min, const double & max){
00368 
00369     int nelem = this->total_space();
00370     if(this->pixelwts==NULL) this->allocate_weights(1);
00371     for(int i=0; i<nelem; i++){
00372       if(this->pixeldata[i]>max || this->pixeldata[i]<min){
00373         if(this->verbose_level) 
00374           cout << "pixel_amp_array::amp_clip - clipping ("
00375                << i/this->axes[0] << "," << i%this->axes[0] << ")\t"
00376                << this->pixeldata[i] << endl;
00377         this->pixeldata[i] = 0;
00378         this->pixelwts[i] = 0;
00379       }
00380     }
00381   }
00382 
00383 
00384   template<class precision>
00385     void pixel_amp_array<precision>::interpolate(){
00386   
00387     int nelem = this->total_space();
00388     int nnonzero;
00389     double sum, wsum;
00390     if(!this->weights_allocated()){
00391       cerr << "pixel_amp_array<precision>::interpolate error - weights are not allocated\n";
00392       throw(std::string("pixel_amp_array<precision>::interpolate"));
00393     }
00394     for(int i=0; i<nelem; i++){
00395       if(this->pixelwts[i] == 0){
00396       
00397         nnonzero = 0;
00398         sum = wsum = 0;
00399         if(i-this->axes[0]>0 && this->pixelwts[i-this->axes[0]]!=0){
00400           nnonzero++; 
00401           sum += this->pixeldata[i-this->axes[0]]*this->pixelwts[i-this->axes[0]];
00402           wsum += this->pixelwts[i-this->axes[0]];
00403         }
00404         if(i+this->axes[0]>0 && this->pixelwts[i+this->axes[0]]!=0){
00405           nnonzero++; 
00406           sum += this->pixeldata[i+this->axes[0]]*this->pixelwts[i+this->axes[0]];
00407           wsum += this->pixelwts[i+this->axes[0]];
00408         }
00409         if(i%this->axes[0]>0 && this->pixelwts[i-1]!=0){
00410           nnonzero++; 
00411           sum += this->pixeldata[i-1]*this->pixelwts[i-1];
00412           wsum += this->pixelwts[i-1];
00413         }
00414         if(i%this->axes[0]<this->axes[0]-1 && this->pixelwts[i+1]!=0){
00415           nnonzero++; 
00416           sum += this->pixeldata[i+1]*this->pixelwts[i+1];
00417           wsum += this->pixelwts[i+1];
00418         }
00419       
00420         if(nnonzero>=3){
00421           if(pixel_array<precision>::verbose_level)
00422             cout << "pixel_amp_array<precision>::interpolate - correcting point " 
00423                  << i/this->axes[0] << ", " << i%this->axes[0] << endl;
00424           this->pixeldata[i] = sum/wsum;
00425           this->pixelwts[i] = wsum;
00426         }
00427       }
00428     }
00429   }
00430     
00431   template<class T>
00432     double pixel_amp_array<T>::fit(const pixel_amp_array<T> & psf, 
00433                                    double & differential_amplitude,
00434                                    vector<double> & relative_offsets,
00435                                    pixel_amp_array<T> & fitted_psf,
00436                                    pixel_amp_array<T> & fit_residual,
00437                                    pixel_amp_array<T> & orig) const {
00438     
00439     if(psf.axes.size()!=2 || this->axes!=psf.axes){
00440       cerr << "pixel_amp_array::fit error - array mismatch\n";
00441       cerr << "this axes " << this->axes[0] << " x " << this->axes[1] << endl;
00442       cerr << "psf axes " << psf.get_axes()[0] << " x " << psf.get_axes()[1] << endl;
00443       throw(string("pixel_amp_array::fit"));
00444     }
00445     if(this->axes[0]<=1 || this->axes[1]<=1 || psf.axes[0]<=1 || psf.axes[1]<=1){
00446       cerr << "pixel_amp_array::fit error - "
00447            << "array doesn't contain enough elements\n";
00448       throw(string("pixel_amp_array::fit")); 
00449     } 
00450 
00451     if(pixel_array<T>::verbose_level)
00452       cout << "pixel_amp_array::fit - seeking offset between arrays of dimension \n"
00453            << this->axes[0] << "x" << this->axes[1]  
00454            << endl;
00455 
00456     pixel_array<T> xcorr_psf = this->cross_correlate(psf);
00457     vector<int> xcorr_minpixel(2,0), xcorr_maxpixel(2,0);
00458 
00459     double min, max;
00460     xcorr_psf.min_and_max(min, xcorr_minpixel, max, xcorr_maxpixel);
00461 
00462     if(pixel_array<T>::verbose_level) {
00463       cout << "pixel_array<T>::fit - xcorr max " 
00464            << xcorr_maxpixel[0] << "\t" 
00465            << xcorr_maxpixel[1] 
00466            << "\t" << max 
00467            << endl;
00468     }
00469 
00470     double xslope = this->axes[1]%2==1 ? 0 : M_PI/2.;
00471     double yslope = this->axes[0]%2==1 ? 0 : M_PI/2.;
00472 
00473     cerr << "xslope " << xslope << " yslope " << yslope << endl;
00474 
00475     double x_halfpix=0, y_halfpix=0;
00476     int x_extrapix=1, y_extrapix=1;
00477     if(this->axes[1]%2==0){
00478       x_halfpix = .5;
00479       x_extrapix = 0;
00480     }
00481     if(this->axes[0]%2==0){
00482       y_halfpix = .5;
00483       y_extrapix = 0;
00484     }
00485 
00486 
00487     if(pixel_array<T>::verbose_level)
00488       cerr << "pixel_amp_array::fit - allocating memory\n";
00489     int nelem = this->axes[0]*this->axes[1];
00490     T * this_arr;
00491     T * psf_arr;
00492     T * diff_arr;
00493     try{
00494       this_arr = new T[2*nelem];
00495       psf_arr = new T[2*nelem];
00496       diff_arr = new T[2*nelem];
00497     } catch(...) {
00498       cerr << "pixel_amp_array::fit error - error allocating memory\n";
00499       throw(string("pixel_amp_array::fit"));
00500     }
00501 
00502     if(pixel_array<T>::verbose_level)
00503       cerr << "pixel_amp_array::fit - filling in arrays\n";
00504     int index;
00505     double amp, phase;
00506     for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++){
00507       for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++){
00508         index = (i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2;
00509 
00510         phase = -xslope*(i+x_halfpix) - yslope*(j+y_halfpix);
00511 
00512         amp = this->pixeldata[index];
00513         this_arr[2*index] = amp*cos(phase);
00514         this_arr[2*index+1] = amp*sin(phase);
00515 
00516         amp = psf.pixeldata[index];
00517         psf_arr[2*index] = amp*cos(phase);
00518         psf_arr[2*index+1] = amp*sin(phase);
00519       }
00520     }
00521 
00522     if(pixel_array<T>::verbose_level)
00523       cerr << "pixel_amp_array::fit - performing transform\n";
00524     Arroyo::fft_manager<T> fft_mgr;  
00525 
00526     vector<long> flipped_axes(2, this->axes[0]);
00527     flipped_axes[0] = this->axes[1];
00528     fft_mgr.forward_fft(flipped_axes, false, true, this_arr);
00529     fft_mgr.forward_fft(flipped_axes, false, true, psf_arr);
00530 
00531     Arroyo::complex_cyclic_permutation(this->axes, 
00532                                        this->axes[0]/2,
00533                                        this->axes[1]/2, 
00534                                        this_arr);
00535 
00536     Arroyo::complex_cyclic_permutation(psf.get_axes(), 
00537                                        psf.get_axes()[0]/2,
00538                                        psf.get_axes()[1]/2, 
00539                                        psf_arr);
00540 
00541 
00542     if(pixel_array<T>::verbose_level)
00543       cerr << "pixel_amp_array::fit - allocating memory\n";
00544     T *real_product, *imag_product;
00545     try{
00546       real_product = new T[nelem];
00547       imag_product = new T[nelem];
00548     } catch(...) {
00549       cerr << "pixel_amp_array::fit error - error allocating memory\n";
00550       throw(string("pixel_amp_array::fit"));
00551     }
00552 
00553     if(pixel_array<T>::verbose_level)
00554       cerr << "pixel_amp_array::fit - computing intermediate arrays\n";
00555     double this_total_power=0, psf_total_power=0, cross_power=0;
00556     for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++){
00557       for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++){
00558         
00559         index = (i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2;
00560 
00561         this_total_power += 
00562           this_arr[2*index]*this_arr[2*index] + this_arr[2*index+1]*this_arr[2*index+1];
00563         psf_total_power += 
00564           psf_arr[2*index]*psf_arr[2*index] + psf_arr[2*index+1]*psf_arr[2*index+1];
00565         
00566         real_product[index] = 
00567           this_arr[2*index]*psf_arr[2*index] + this_arr[2*index+1]*psf_arr[2*index+1];
00568         imag_product[index] = 
00569           this_arr[2*index+1]*psf_arr[2*index] - this_arr[2*index]*psf_arr[2*index+1];
00570         
00571         cross_power += real_product[index];
00572       }
00573     }
00574 
00575     if(pixel_array<T>::verbose_level)
00576       cout << "This total power "
00577            << this_total_power 
00578            << " PSF total power "
00579            << psf_total_power
00580            << " cross power "
00581            << cross_power
00582            << endl;
00583 
00584     // Perform a search for the best fitting fractional offset.
00585     double faca = 2*M_PI/(double)(this->axes[0]);
00586     double facb = 2*M_PI/(double)(this->axes[1]);
00587     double dcross_du, dcross_dv;
00588     double dsqcross_dusq, dsqcross_dvsq, dsqcross_dudv;
00589     //double x_offset=-xcorr_maxpixel[0], y_offset=-xcorr_maxpixel[1];
00590     double x_offset=0, y_offset=0;
00591     double delta_x_offset, delta_y_offset;
00592     double real_part_of_cross_term;
00593     double deriv_real_part_of_cross_term;
00594     double sqderiv_real_part_of_cross_term;
00595     double sum_real_part_of_cross_term;
00596     double chisq, last_chisq=DBL_MAX;
00597     while(1){
00598       dcross_du = dcross_dv = dsqcross_dusq = dsqcross_dvsq = dsqcross_dudv = 0;
00599       sum_real_part_of_cross_term = 0;
00600       for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++){
00601         for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++){
00602 
00603           index = (i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2;
00604 
00605           real_part_of_cross_term = 
00606             real_product[index] * cos(i*y_offset*facb + j*x_offset*faca) +
00607             imag_product[index] * sin(i*y_offset*facb + j*x_offset*faca);
00608 
00609           sum_real_part_of_cross_term += 
00610             real_part_of_cross_term;
00611 
00612           deriv_real_part_of_cross_term = 
00613             -1 * real_product[index] * sin(i*y_offset*facb + j*x_offset*faca) +
00614             imag_product[index] * cos(i*y_offset*facb + j*x_offset*faca);
00615 
00616           dcross_du += i*facb*deriv_real_part_of_cross_term;
00617           dcross_dv += j*faca*deriv_real_part_of_cross_term;
00618 
00619           sqderiv_real_part_of_cross_term = 
00620             -1 * real_product[index] * cos(i*y_offset*facb + j*x_offset*faca) -
00621             imag_product[index] * sin(i*y_offset*facb + j*x_offset*faca);
00622           
00623           dsqcross_dusq += i*i*facb*facb*sqderiv_real_part_of_cross_term;
00624           dsqcross_dudv += i*j*facb*faca*sqderiv_real_part_of_cross_term;
00625           dsqcross_dvsq += j*j*faca*faca*sqderiv_real_part_of_cross_term;
00626         }
00627       }
00628 
00629       differential_amplitude = fabs(cross_power / psf_total_power);
00630 
00631       chisq = .5*(this_total_power + 
00632                   differential_amplitude*differential_amplitude*psf_total_power - 
00633                   2*differential_amplitude*sum_real_part_of_cross_term);
00634 
00636       // Compute chi squared
00637       double angle, real, imag, real_arg=0, imag_arg=0, xchisq=0, xxchisq=0;
00638       for(int u=-this->axes[1]/2; u<this->axes[1]/2+x_extrapix; u++){
00639         for(int v=-this->axes[0]/2; v<this->axes[0]/2+y_extrapix; v++){
00640           index = (u+this->axes[1]/2)*this->axes[0]+v+this->axes[0]/2;
00641                 
00642           real = imag = 0;
00643           angle = -(y_offset*facb*u + x_offset*faca*v);
00644           real += differential_amplitude*cos(angle);
00645           imag += differential_amplitude*sin(angle);
00646         
00647           real_arg = this_arr[2*index] - psf_arr[2*index]*real - psf_arr[2*index+1]*imag;
00648           imag_arg = this_arr[2*index+1] - psf_arr[2*index+1]*real + psf_arr[2*index]*imag;
00649 
00650           xchisq += .5*(real_arg*real_arg + imag_arg*imag_arg);
00651 
00652           xxchisq += 
00653             real_product[index] * cos(angle) -
00654             imag_product[index] * sin(angle);
00655 
00656         }
00657       }
00658       double tmp_xxchisq = .5*(this_total_power + 
00659                                differential_amplitude*differential_amplitude*psf_total_power - 
00660                                2*differential_amplitude*xxchisq);
00662 
00663       if(pixel_array<T>::verbose_level)
00664         cout << " chisq " << chisq
00665              << " xchisq " << xchisq
00666              << " xxchisq " << tmp_xxchisq
00667              << " amp " << differential_amplitude
00668              << "\t";
00669 
00670 
00671       // Find the zero in two dimensions
00672       double denom = dsqcross_dusq*dsqcross_dvsq - dsqcross_dudv*dsqcross_dudv;
00673       delta_y_offset = (dcross_du*dsqcross_dvsq - dcross_dv*dsqcross_dudv)/denom;
00674       delta_x_offset = (-dcross_du*dsqcross_dudv + dcross_dv*dsqcross_dusq)/denom;
00675 
00676       if(pixel_array<T>::verbose_level)
00677         cerr << "dcross_du " << dcross_du 
00678              << " dcross_dv " << dcross_dv
00679              << " dsqcross_dusq " << dsqcross_dusq
00680              << " dsqcross_dudv " << dsqcross_dudv
00681              << " dsqcross_dvsq " << dsqcross_dvsq
00682              << " delta_x " << delta_x_offset
00683              << " delta_y " << delta_y_offset
00684              << endl;
00685 
00686       x_offset-=delta_x_offset;
00687       y_offset-=delta_y_offset;
00688 
00689       differential_amplitude = sum_real_part_of_cross_term / psf_total_power;
00690       
00691       chisq = .5*(this_total_power + 
00692                   differential_amplitude*differential_amplitude*psf_total_power - 
00693                   2*differential_amplitude*sum_real_part_of_cross_term);
00694 
00696       // Compute chi squared
00697       real_arg = imag_arg = xchisq = 0;
00698       double ychisq = 0;
00699       for(int u=-this->axes[1]/2; u<this->axes[1]/2+x_extrapix; u++){
00700         for(int v=-this->axes[0]/2; v<this->axes[0]/2+y_extrapix; v++){
00701           index = (u+this->axes[1]/2)*this->axes[0]+v+this->axes[0]/2;
00702                 
00703           real = imag = 0;
00704           angle = -(y_offset*facb*u + x_offset*faca*v);
00705           real += differential_amplitude*cos(angle);
00706           imag += differential_amplitude*sin(angle);
00707           
00708           real_arg = this_arr[2*index] - psf_arr[2*index]*real - psf_arr[2*index+1]*imag;
00709           imag_arg = this_arr[2*index+1] - psf_arr[2*index+1]*real + psf_arr[2*index]*imag;
00710 
00711           ychisq += .5*(real_arg*real_arg + imag_arg*imag_arg);
00712 
00713         }
00714       }
00715 
00717 
00718       if(pixel_array<T>::verbose_level)
00719         cout << " chisq " << chisq
00720              << " xchisq " << ychisq
00721              << " xt " << sum_real_part_of_cross_term
00722              << " amp " << differential_amplitude
00723              << " off " << x_offset 
00724              << " " << delta_x_offset 
00725              << " " << y_offset 
00726              << " " << delta_y_offset 
00727              << endl;
00728 
00729       /*
00730       if(last_chisq<chisq)
00731         break;
00732       else 
00733         last_chisq = chisq;
00734       */
00735       if(fabs(delta_x_offset)<1e-6 &&
00736          fabs(delta_y_offset)<1e-6)
00737         break;
00738 
00739     }
00740 
00741     relative_offsets.resize(2);
00742     relative_offsets[0] = x_offset;
00743     relative_offsets[1] = y_offset;
00744 
00745     // Transform back to get residual from fit
00746     if(pixel_array<T>::verbose_level)
00747       cerr << "pixel_amp_array::fit - computing residuals\n";
00748 
00749     double this_real, this_imag;
00750     for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++){
00751       for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++){
00752         index = (i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2;
00753 
00754         amp = 
00755           differential_amplitude*
00756           sqrt(psf_arr[2*index]*psf_arr[2*index] + 
00757                psf_arr[2*index+1]*psf_arr[2*index+1]);
00758 
00759         /*
00760         phase = 
00761           atan2(psf_arr[2*index+1],psf_arr[2*index]) - 
00762           i*y_offset*facb -
00763           j*x_offset*faca - 
00764           xslope*(i+x_halfpix) -
00765           yslope*(j+y_halfpix);
00766         */
00767 
00768         phase = 
00769           atan2(psf_arr[2*index+1],psf_arr[2*index]) + 
00770           i*y_offset*facb + j*x_offset*faca;
00771 
00772 
00773         psf_arr[2*index] = amp*cos(phase);
00774         psf_arr[2*index+1] = amp*sin(phase);
00775 
00776         diff_arr[2*index] = this_arr[2*index] - amp*cos(phase);
00777         diff_arr[2*index+1] = this_arr[2*index+1] - amp*sin(phase);
00778 
00779       }
00780     }
00781 
00782 
00783     Arroyo::complex_cyclic_permutation(this->get_axes(), 
00784                                        -this->get_axes()[0]/2,
00785                                        -this->get_axes()[1]/2, 
00786                                        psf_arr);
00787     
00788     Arroyo::complex_cyclic_permutation(this->get_axes(), 
00789                                        -this->get_axes()[0]/2,
00790                                        -this->get_axes()[1]/2, 
00791                                        this_arr);
00792 
00793     Arroyo::complex_cyclic_permutation(this->get_axes(), 
00794                                        -this->get_axes()[0]/2,
00795                                        -this->get_axes()[1]/2, 
00796                                        diff_arr);
00797 
00798     fft_mgr.backward_fft(flipped_axes, false, true, this_arr);
00799     fft_mgr.backward_fft(flipped_axes, false, true, psf_arr);
00800     fft_mgr.backward_fft(flipped_axes, false, true, diff_arr);
00801 
00802     double norm_fac = 1/(double)(this->total_space());
00803     //double norm_fac = 1;
00804     for(int i=0; i<nelem; i++){
00805       psf_arr[i] = norm_fac*psf_arr[2*i];
00806       this_arr[i] = norm_fac*this_arr[2*i];
00807 
00808       /*
00809       psf_arr[i] = norm_fac*
00810         sqrt(psf_arr[2*i]*psf_arr[2*i]+
00811              psf_arr[2*i+1]*psf_arr[2*i+1]);
00812       this_arr[i] = norm_fac*
00813         sqrt(this_arr[2*i]*this_arr[2*i]+
00814              this_arr[2*i+1]*this_arr[2*i+1]);
00815       */
00816     }
00817 
00818     fitted_psf = pixel_array<T>(this->axes, psf_arr);
00819     orig = pixel_array<T>(this->axes, this_arr);
00820 
00821     fit_residual = orig - fitted_psf;
00822 
00823     // Clean up
00824     if(pixel_array<T>::verbose_level)
00825       cerr << "pixel_amp_array::fit - cleaning up\n";
00826 
00827     delete [] this_arr;
00828     delete [] psf_arr;
00829     delete [] diff_arr;
00830     delete [] real_product;
00831     delete [] imag_product;
00832 
00833     return(chisq);
00834   }
00835 
00836 
00837   template<class T>
00838     double pixel_amp_array<T>::fit(const pixel_amp_array<T> & psf, 
00839                                    double & differential_amplitude,
00840                                    double & offset,
00841                                    bool fit_for_offset,
00842                                    vector<double> & relative_offsets,
00843                                    pixel_amp_array<T> & fitted_psf,
00844                                    pixel_amp_array<T> & fit_residual,
00845                                    pixel_amp_array<T> & orig) const {
00846     
00847     if(psf.axes.size()!=2 || this->axes!=psf.axes){
00848       cerr << "pixel_amp_array::fit error - array mismatch\n";
00849       cerr << "this axes " << this->axes[0] << " x " << this->axes[1] << endl;
00850       cerr << "psf axes " << psf.get_axes()[0] << " x " << psf.get_axes()[1] << endl;
00851       throw(string("pixel_amp_array::fit"));
00852     }
00853     if(this->axes[0]<=1 || this->axes[1]<=1 || psf.axes[0]<=1 || psf.axes[1]<=1){
00854       cerr << "pixel_amp_array::fit error - "
00855            << "array doesn't contain enough elements\n";
00856       throw(string("pixel_amp_array::fit")); 
00857     } 
00858 
00859     if(pixel_array<T>::verbose_level)
00860       cout << "pixel_amp_array::fit - seeking offset between arrays of dimension \n"
00861            << this->axes[0] << "x" << this->axes[1]  
00862            << endl;
00863 
00864     pixel_array<T> xcorr_psf = this->cross_correlate(psf);
00865     vector<int> xcorr_minpixel(2,0), xcorr_maxpixel(2,0);
00866 
00867     double min, max;
00868     xcorr_psf.min_and_max(min, xcorr_minpixel, max, xcorr_maxpixel);
00869 
00870     if(pixel_array<T>::verbose_level) {
00871       cout << "pixel_array<T>::fit - xcorr max " 
00872            << xcorr_maxpixel[0] << "\t" 
00873            << xcorr_maxpixel[1] 
00874            << "\t" << max 
00875            << endl;
00876     }
00877 
00878     double xslope = this->axes[1]%2==1 ? 0 : M_PI/2.;
00879     double yslope = this->axes[0]%2==1 ? 0 : M_PI/2.;
00880 
00881     
00882     if(pixel_array<T>::verbose_level)
00883       cerr << "pixel_amp_array::fit - xslope " << xslope << " yslope " << yslope << endl;
00884 
00885     double x_halfpix=0, y_halfpix=0;
00886     int x_extrapix=1, y_extrapix=1;
00887     if(this->axes[1]%2==0){
00888       x_halfpix = .5;
00889       x_extrapix = 0;
00890     }
00891     if(this->axes[0]%2==0){
00892       y_halfpix = .5;
00893       y_extrapix = 0;
00894     }
00895 
00896 
00897     if(pixel_array<T>::verbose_level)
00898       cerr << "pixel_amp_array::fit - allocating memory\n";
00899     int nelem = this->axes[0]*this->axes[1];
00900     T * this_arr;
00901     T * psf_arr;
00902     try{
00903       this_arr = new T[2*nelem];
00904       psf_arr = new T[2*nelem];
00905     } catch(...) {
00906       cerr << "pixel_amp_array::fit error - error allocating memory\n";
00907       throw(string("pixel_amp_array::fit"));
00908     }
00909 
00910     if(pixel_array<T>::verbose_level)
00911       cerr << "pixel_amp_array::fit - filling in arrays\n";
00912     int index;
00913     double amp, phase;
00914     for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++){
00915       for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++){
00916         index = (i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2;
00917 
00918         phase = -xslope*(i+x_halfpix) - yslope*(j+y_halfpix);
00919 
00920         amp = this->pixeldata[index];
00921         this_arr[2*index] = amp*cos(phase);
00922         this_arr[2*index+1] = amp*sin(phase);
00923 
00924         amp = psf.pixeldata[index];
00925         psf_arr[2*index] = amp*cos(phase);
00926         psf_arr[2*index+1] = amp*sin(phase);
00927       }
00928     }
00929 
00930     if(pixel_array<T>::verbose_level)
00931       cerr << "pixel_amp_array::fit - performing transform\n";
00932     Arroyo::fft_manager<T> fft_mgr;  
00933 
00934     vector<long> flipped_axes(2, this->axes[0]);
00935     flipped_axes[0] = this->axes[1];
00936     fft_mgr.forward_fft(flipped_axes, false, true, this_arr);
00937     fft_mgr.forward_fft(flipped_axes, false, true, psf_arr);
00938 
00939     double this_dc = this_arr[0];
00940     double psf_dc = psf_arr[0];
00941     double this_dc_0 = this_arr[0];
00942     double this_dc_1 = this_arr[1];
00943     double psf_dc_0 = psf_arr[0];
00944     double psf_dc_1 = psf_arr[1];
00945 
00946     Arroyo::complex_cyclic_permutation(this->axes, 
00947                                        this->axes[0]/2,
00948                                        this->axes[1]/2, 
00949                                        this_arr);
00950 
00951     Arroyo::complex_cyclic_permutation(psf.get_axes(), 
00952                                        psf.get_axes()[0]/2,
00953                                        psf.get_axes()[1]/2, 
00954                                        psf_arr);
00955 
00956 
00957     if(pixel_array<T>::verbose_level)
00958       cerr << "pixel_amp_array::fit - allocating memory\n";
00959     T *real_product, *imag_product;
00960     try{
00961       real_product = new T[nelem];
00962       imag_product = new T[nelem];
00963     } catch(...) {
00964       cerr << "pixel_amp_array::fit error - error allocating memory\n";
00965       throw(string("pixel_amp_array::fit"));
00966     }
00967 
00968     if(pixel_array<T>::verbose_level)
00969       cerr << "pixel_amp_array::fit - computing intermediate arrays\n";
00970     double this_total_power=0, psf_total_power=0, cross_power=0;
00971     for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++){
00972       for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++){
00973         
00974         index = (i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2;
00975 
00976         this_total_power += 
00977           this_arr[2*index]*this_arr[2*index] + this_arr[2*index+1]*this_arr[2*index+1];
00978         psf_total_power += 
00979           psf_arr[2*index]*psf_arr[2*index] + psf_arr[2*index+1]*psf_arr[2*index+1];
00980         
00981         real_product[index] = 
00982           this_arr[2*index]*psf_arr[2*index] + this_arr[2*index+1]*psf_arr[2*index+1];
00983         imag_product[index] = 
00984           this_arr[2*index+1]*psf_arr[2*index] - this_arr[2*index]*psf_arr[2*index+1];
00985         
00986         cross_power += real_product[index];
00987       }
00988     }
00989 
00990     if(pixel_array<T>::verbose_level)
00991       cout << "This total power "
00992            << this_total_power 
00993            << " PSF total power "
00994            << psf_total_power
00995            << " cross power "
00996            << cross_power << endl
00997            << " this dc " << this_arr[nelem]
00998            << "\t" << this_arr[nelem+1] 
00999            << "\t" << this_dc_0 
01000            << "\t" << this_dc_1 
01001            << endl
01002            << " psf dc " << psf_arr[nelem] 
01003            << "\t" << psf_arr[nelem+1] 
01004            << "\t" << psf_dc_0 
01005            << "\t" << psf_dc_1 
01006            << endl;
01007 
01008     // Perform a search for the best fitting fractional offset.
01009     double faca = 2*M_PI/(double)(this->axes[0]);
01010     double facb = 2*M_PI/(double)(this->axes[1]);
01011     double dcross_du, dcross_dv;
01012     double dsqcross_dusq, dsqcross_dvsq, dsqcross_dudv;
01013     double x_offset=0, y_offset=0;
01014     double delta_x_offset, delta_y_offset;
01015     double real_part_of_cross_term;
01016     double deriv_real_part_of_cross_term;
01017     double sqderiv_real_part_of_cross_term;
01018     double sum_real_part_of_cross_term;
01019     double chisq, last_chisq=DBL_MAX;
01020     while(1){
01021       dcross_du = dcross_dv = dsqcross_dusq = dsqcross_dvsq = dsqcross_dudv = 0;
01022       sum_real_part_of_cross_term = 0;
01023       for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++){
01024         for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++){
01025 
01026           index = (i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2;
01027 
01028           real_part_of_cross_term = 
01029             real_product[index] * cos(i*y_offset*facb + j*x_offset*faca) +
01030             imag_product[index] * sin(i*y_offset*facb + j*x_offset*faca);
01031 
01032           sum_real_part_of_cross_term += 
01033             real_part_of_cross_term;
01034 
01035           deriv_real_part_of_cross_term = 
01036             -1 * real_product[index] * sin(i*y_offset*facb + j*x_offset*faca) +
01037             imag_product[index] * cos(i*y_offset*facb + j*x_offset*faca);
01038 
01039           dcross_du += i*facb*deriv_real_part_of_cross_term;
01040           dcross_dv += j*faca*deriv_real_part_of_cross_term;
01041 
01042           sqderiv_real_part_of_cross_term = 
01043             -1 * real_product[index] * cos(i*y_offset*facb + j*x_offset*faca) -
01044             imag_product[index] * sin(i*y_offset*facb + j*x_offset*faca);
01045           
01046           dsqcross_dusq += i*i*facb*facb*sqderiv_real_part_of_cross_term;
01047           dsqcross_dudv += i*j*facb*faca*sqderiv_real_part_of_cross_term;
01048           dsqcross_dvsq += j*j*faca*faca*sqderiv_real_part_of_cross_term;
01049         }
01050       }
01051 
01052       // Find the zero in two dimensions
01053       double denom = dsqcross_dusq*dsqcross_dvsq - dsqcross_dudv*dsqcross_dudv;
01054       delta_y_offset = (dcross_du*dsqcross_dvsq - dcross_dv*dsqcross_dudv)/denom;
01055       delta_x_offset = (-dcross_du*dsqcross_dudv + dcross_dv*dsqcross_dusq)/denom;
01056       x_offset-=delta_x_offset;
01057       y_offset-=delta_y_offset;
01058 
01059       if(pixel_array<T>::verbose_level)
01060         cerr << "dcross_du " << dcross_du 
01061              << " dcross_dv " << dcross_dv
01062              << " dsqcross_dusq " << dsqcross_dusq
01063              << " dsqcross_dudv " << dsqcross_dudv
01064              << " dsqcross_dvsq " << dsqcross_dvsq
01065              << " delta_x " << delta_x_offset
01066              << " delta_y " << delta_y_offset
01067              << endl;
01068 
01069       if(!fit_for_offset){
01070         differential_amplitude = sum_real_part_of_cross_term / psf_total_power;
01071         offset = 0;
01072       } else {
01073         denom = psf_total_power - psf_dc*psf_dc;
01074         differential_amplitude = (sum_real_part_of_cross_term - psf_dc*this_dc)/denom;
01075         offset = (-sum_real_part_of_cross_term*psf_dc + psf_total_power*this_dc)/denom;
01076       }
01077       chisq = .5*(this_total_power + 
01078                   differential_amplitude*differential_amplitude*psf_total_power - 
01079                   2*differential_amplitude*sum_real_part_of_cross_term +
01080                   2*differential_amplitude*offset*psf_dc -
01081                   2*offset*this_dc +
01082                   offset*offset);
01083 
01085       // Compute chi squared
01086       double angle, real, imag, real_arg=0, imag_arg=0, ychisq=0;
01087       for(int u=-this->axes[1]/2; u<this->axes[1]/2+x_extrapix; u++){
01088         for(int v=-this->axes[0]/2; v<this->axes[0]/2+y_extrapix; v++){
01089           index = (u+this->axes[1]/2)*this->axes[0]+v+this->axes[0]/2;
01090                 
01091           real = imag = 0;
01092           angle = -(y_offset*facb*u + x_offset*faca*v);
01093           real += differential_amplitude*cos(angle);
01094           imag += differential_amplitude*sin(angle);
01095           
01096           real_arg = this_arr[2*index] - psf_arr[2*index]*real - psf_arr[2*index+1]*imag;
01097           imag_arg = this_arr[2*index+1] - psf_arr[2*index+1]*real + psf_arr[2*index]*imag;
01098 
01099           ychisq += .5*(real_arg*real_arg + imag_arg*imag_arg);
01100 
01101         }
01102       }
01103 
01105 
01106       if(pixel_array<T>::verbose_level){
01107         cout << " chisq " << chisq
01108              << " ychisq " << ychisq
01109              << " xt " << sum_real_part_of_cross_term
01110              << " amp " << differential_amplitude;
01111         if(fit_for_offset)
01112           cout << " offset " << offset;
01113         
01114         cout << " shift " << x_offset 
01115              << " " << delta_x_offset 
01116              << " " << y_offset 
01117              << " " << delta_y_offset 
01118              << endl;
01119       }
01120 
01121       /*
01122       if(last_chisq<chisq)
01123         break;
01124       else 
01125         last_chisq = chisq;
01126       */
01127       if(fabs(delta_x_offset)<1e-6 &&
01128          fabs(delta_y_offset)<1e-6)
01129         break;
01130 
01131     }
01132 
01133     relative_offsets.resize(2);
01134     relative_offsets[0] = x_offset;
01135     relative_offsets[1] = y_offset;
01136 
01137     // Transform back to get residual from fit
01138     if(pixel_array<T>::verbose_level)
01139       cerr << "pixel_amp_array::fit - computing residuals\n";
01140 
01141     double this_real, this_imag;
01142     for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++){
01143       for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++){
01144         index = (i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2;
01145 
01146         amp = 
01147           differential_amplitude*
01148           sqrt(psf_arr[2*index]*psf_arr[2*index] + 
01149                psf_arr[2*index+1]*psf_arr[2*index+1]);
01150 
01151         /*
01152         phase = 
01153           atan2(psf_arr[2*index+1],psf_arr[2*index]) - 
01154           i*y_offset*facb -
01155           j*x_offset*faca - 
01156           xslope*(i+x_halfpix) -
01157           yslope*(j+y_halfpix);
01158         */
01159 
01160         phase = 
01161           atan2(psf_arr[2*index+1],psf_arr[2*index]) + 
01162           i*y_offset*facb + j*x_offset*faca;
01163 
01164 
01165         psf_arr[2*index] = amp*cos(phase);
01166         psf_arr[2*index+1] = amp*sin(phase);
01167 
01168       }
01169     }
01170 
01171 
01172     Arroyo::complex_cyclic_permutation(this->get_axes(), 
01173                                        -this->get_axes()[0]/2,
01174                                        -this->get_axes()[1]/2, 
01175                                        psf_arr);
01176     
01177     Arroyo::complex_cyclic_permutation(this->get_axes(), 
01178                                        -this->get_axes()[0]/2,
01179                                        -this->get_axes()[1]/2, 
01180                                        this_arr);
01181 
01182     psf_arr[0] += offset;
01183 
01184     fft_mgr.backward_fft(flipped_axes, false, true, this_arr);
01185     fft_mgr.backward_fft(flipped_axes, false, true, psf_arr);
01186 
01187     double norm_fac = 1/(double)(this->total_space());
01188     //double norm_fac = 1;
01189     for(int i=0; i<nelem; i++){
01190       psf_arr[i] = norm_fac*psf_arr[2*i];
01191       this_arr[i] = norm_fac*this_arr[2*i];
01192 
01193       /*
01194       psf_arr[i] = norm_fac*
01195         sqrt(psf_arr[2*i]*psf_arr[2*i]+
01196              psf_arr[2*i+1]*psf_arr[2*i+1]);
01197       this_arr[i] = norm_fac*
01198         sqrt(this_arr[2*i]*this_arr[2*i]+
01199              this_arr[2*i+1]*this_arr[2*i+1]);
01200       */
01201     }
01202 
01203     fitted_psf = pixel_array<T>(this->axes, psf_arr);
01204     orig = pixel_array<T>(this->axes, this_arr);
01205 
01206     fit_residual = orig - fitted_psf;
01207 
01208     double mean, rms;
01209     fit_residual.mean_and_rms(mean, rms);
01210 
01211     // Clean up
01212     if(pixel_array<T>::verbose_level)
01213       cerr << "pixel_amp_array::fit - cleaning up\n";
01214 
01215     delete [] this_arr;
01216     delete [] psf_arr;
01217     delete [] real_product;
01218     delete [] imag_product;
01219 
01220     return(chisq);
01221   }
01222 
01223   template<class T>
01224     double pixel_amp_array<T>::fit(int npsfs,
01225                                    const pixel_amp_array<T> & psf, 
01226                                    vector<double> & differential_amplitudes,
01227                                    vector<vector<double> > & relative_offsets,
01228                                    pixel_amp_array<T> & fitted_model,
01229                                    pixel_amp_array<T> & fit_residual) const {
01230     
01231 
01232     
01233     if(npsfs<=0){
01234       cerr << "pixel_amp_array::fit error - cannot perform a fit to "
01235            << npsfs
01236            << " PSF's\n";
01237       throw(string("pixel_amp_array::fit"));
01238     }
01239 
01240     if(psf.axes.size()!=2 || this->axes!=psf.axes){
01241       cerr << "pixel_amp_array::fit error - array mismatch\n";
01242       cerr << "this axes " << this->axes[0] << " x " << this->axes[1] << endl;
01243       cerr << "psf axes " << psf.get_axes()[0] << " x " << psf.get_axes()[1] << endl;
01244       throw(string("pixel_amp_array::fit"));
01245     }
01246     if(this->axes[0]<=1 || this->axes[1]<=1 || psf.axes[0]<=1 || psf.axes[1]<=1){
01247       cerr << "pixel_amp_array::fit error - "
01248            << "array doesn't contain enough elements\n";
01249       throw(string("pixel_amp_array::fit")); 
01250     } 
01251 
01252 
01253     if(pixel_array<T>::verbose_level)
01254       cout << "pixel_amp_array::fit - seeking offset between arrays of dimension \n"
01255            << this->axes[0] << "x" << this->axes[1]  
01256            << endl;
01257 
01258     pixel_array<T> xcorr_psf = this->cross_correlate(psf);
01259     vector<int> xcorr_minpixel(2,0), xcorr_maxpixel(2,0);
01260 
01261     double min, max;
01262     xcorr_psf.min_and_max(min, xcorr_minpixel, max, xcorr_maxpixel);
01263 
01264     if(pixel_array<T>::verbose_level) {
01265       cout << "pixel_array<T>::fit - xcorr max " 
01266            << xcorr_maxpixel[0] << "\t" 
01267            << xcorr_maxpixel[1] 
01268            << "\t" << max 
01269            << endl;
01270     }
01271 
01272     double xslope = this->axes[1]%2==1 ? 0 : M_PI/2.;
01273     double yslope = this->axes[0]%2==1 ? 0 : M_PI/2.;
01274 
01275     double x_halfpix=0, y_halfpix=0;
01276     int x_extrapix=1, y_extrapix=1;
01277     if(this->axes[1]%2==0){
01278       x_halfpix = .5;
01279       x_extrapix = 0;
01280     }
01281     if(this->axes[0]%2==0){
01282       y_halfpix = .5;
01283       y_extrapix = 0;
01284     }
01285 
01286 
01287     if(pixel_array<T>::verbose_level)
01288       cerr << "pixel_amp_array::fit - allocating memory\n";
01289     int nelem = this->total_space();
01290     T * this_arr;
01291     T * psf_arr;
01292     T * fit_arr;
01293     try{
01294       this_arr = new T[2*nelem];
01295       psf_arr = new T[2*nelem];
01296       fit_arr = new T[2*nelem];
01297     } catch(...) {
01298       cerr << "pixel_amp_array::fit error - error allocating memory\n";
01299       throw(string("pixel_amp_array::fit"));
01300     }
01301 
01302     if(pixel_array<T>::verbose_level)
01303       cerr << "pixel_amp_array::fit - filling in arrays\n";
01304     int index;
01305     double amp, phase;
01306     for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++){
01307       for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++){
01308         index = (i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2;
01309 
01310         phase = -xslope*(i+x_halfpix) - yslope*(j+y_halfpix);
01311 
01312         amp = this->pixeldata[index]/(double)nelem;
01313         this_arr[2*index] = amp*cos(phase);
01314         this_arr[2*index+1] = amp*sin(phase);
01315 
01316         amp = psf.pixeldata[index]/(double)nelem;
01317         psf_arr[2*index] = amp*cos(phase);
01318         psf_arr[2*index+1] = amp*sin(phase);
01319       }
01320     }
01321 
01322     if(pixel_array<T>::verbose_level)
01323       cerr << "pixel_amp_array::fit - performing transform\n";
01324     Arroyo::fft_manager<T> fft_mgr;  
01325 
01326     vector<long> flipped_axes(2, this->axes[0]);
01327     flipped_axes[0] = this->axes[1];
01328     fft_mgr.forward_fft(flipped_axes, false, true, this_arr);
01329     fft_mgr.forward_fft(flipped_axes, false, true, psf_arr);
01330 
01331     Arroyo::complex_cyclic_permutation(this->axes, 
01332                                        this->axes[0]/2,
01333                                        this->axes[1]/2, 
01334                                        this_arr);
01335 
01336     Arroyo::complex_cyclic_permutation(psf.get_axes(), 
01337                                        psf.get_axes()[0]/2,
01338                                        psf.get_axes()[1]/2, 
01339                                        psf_arr);
01340 
01341     if(pixel_array<T>::verbose_level)
01342       cerr << "pixel_amp_array::fit - allocating memory\n";
01343     T *real_cross_product, *imag_cross_product, *psf_power;
01344     try{
01345       real_cross_product = new T[nelem];
01346       imag_cross_product = new T[nelem];
01347       psf_power = new T[nelem];
01348     } catch(...) {
01349       cerr << "pixel_amp_array::fit error - error allocating memory\n";
01350       throw(string("pixel_amp_array::fit"));
01351     }
01352 
01353     if(pixel_array<T>::verbose_level)
01354       cerr << "pixel_amp_array::fit - computing intermediate arrays\n";
01355     double this_total_power=0, psf_total_power=0, cross_power=0;
01356     for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++){
01357       for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++){
01358         
01359         index = (i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2;
01360 
01361         this_total_power += 
01362           this_arr[2*index]*this_arr[2*index] + this_arr[2*index+1]*this_arr[2*index+1];
01363 
01364         psf_power[index] = 
01365           (psf_arr[2*index]*psf_arr[2*index] + psf_arr[2*index+1]*psf_arr[2*index+1]);
01366         psf_total_power += psf_power[index];
01367         
01368         real_cross_product[index] = 
01369           (this_arr[2*index]*psf_arr[2*index] + this_arr[2*index+1]*psf_arr[2*index+1]);
01370         imag_cross_product[index] = 
01371           (this_arr[2*index]*psf_arr[2*index+1] - this_arr[2*index+1]*psf_arr[2*index]);
01372         
01373         cross_power += real_cross_product[index];
01374       }
01375     }
01376 
01377     if(pixel_array<T>::verbose_level)
01378       cout << "This total power "
01379            << this_total_power 
01380            << " PSF total power "
01381            << psf_total_power
01382            << " cross power "
01383            << cross_power
01384            << endl;
01385 
01386     // Perform a search for the best fitting fractional offset.
01387     double facx = 2*M_PI/(double)(this->axes[0]);
01388     double facy = 2*M_PI/(double)(this->axes[1]);
01389     double chisq, last_chisq=DBL_MAX;
01390 
01391     differential_amplitudes = 
01392       vector<double>(npsfs, fabs(cross_power/psf_total_power));
01393     relative_offsets.resize(npsfs);
01394     for(int i=0; i<npsfs; i++)
01395       relative_offsets[i].resize(2);
01396 
01397     vector<double> incr_differential_amplitudes(npsfs);
01398     vector<vector<double> > incr_relative_offsets(npsfs);
01399     for(int i=0; i<npsfs; i++)
01400       incr_relative_offsets[i].resize(2);
01401 
01402 
01403 
01404     // Setup stuff for the SVD
01405     if(pixel_array<T>::verbose_level)
01406       cout << "svd setup\n";
01407 
01408     char jobu[1];
01409     char jobvt[1];
01410     bool store_eigenmodes = true;
01411     if(store_eigenmodes)
01412       jobu[0] = jobvt[0] = 'A';
01413     else 
01414       jobu[0] = jobvt[0] = 'S';
01415     int lwork=-1, info;
01416     T optimal_workspace_size;
01417     T *singular_values, *g_gtranspose_eigenmode_data, *gtranspose_g_eigenmode_data, *work;
01418 
01419 
01420     T * matrix;
01421     int matrix_dimen = 3*npsfs;
01422     try{
01423       int nelem = matrix_dimen*matrix_dimen;
01424       matrix = new T[nelem];
01425       for(int i=0; i<nelem; i++)
01426         matrix[i] = 0;
01427     } catch(...){
01428       cerr << "pixel_amp_array::fit error - "
01429            << "unable to allocate " 
01430            << nelem
01431            << " elements of memory\n";
01432       throw(string("pixel_amp_array::fit"));
01433     }
01434 
01435     int axes_0 = matrix_dimen;
01436     int axes_1 = matrix_dimen;
01437     
01438     singular_value_decomposition<T>(jobu, 
01439                                     jobvt, 
01440                                     axes_0,
01441                                     axes_1, 
01442                                     matrix,
01443                                     axes_0, 
01444                                     singular_values, 
01445                                     g_gtranspose_eigenmode_data, 
01446                                     axes_0, 
01447                                     gtranspose_g_eigenmode_data, 
01448                                     axes_1,
01449                                     &optimal_workspace_size, 
01450                                     lwork, 
01451                                     info);
01452     
01453     lwork = (int)optimal_workspace_size;
01454     
01455     try{
01456       singular_values = new T[this->axes[1]];
01457       if(store_eigenmodes)
01458         g_gtranspose_eigenmode_data = new T[this->axes[0]*this->axes[0]];
01459       else
01460         g_gtranspose_eigenmode_data = new T[this->axes[0]*this->axes[1]];
01461       gtranspose_g_eigenmode_data = new T[this->axes[1]*this->axes[1]];
01462       work = new T[(int)(optimal_workspace_size)];
01463     } catch(...) {
01464       cerr << "pixel_amp_array::fit error - "
01465            << "unable to allocate memory to perform the singular value decomposition\n";
01466       throw(string("pixel_amp_array::fit"));
01467     }
01468 
01469 
01470     double real, imag;
01471     double tmp, tmp2, tmp3;
01472     double angle, diff_angle, real_sum_exps, imag_sum_exps;
01473     double omega, xi;
01474     vector<double> dchisq_dx(npsfs), dchisq_dy(npsfs), dchisq_db(npsfs);
01475 
01476     while(1){
01477 
01478       // Compute matrix elements and first derivatives
01479       
01480       for(int r=0; r<npsfs; r++){
01481         for(int s=r; s<npsfs; s++){
01482 
01483           dchisq_dx[r] = dchisq_dy[r] = dchisq_db[r] = 0;
01484 
01485           for(int u=-this->axes[1]/2; u<this->axes[1]/2+x_extrapix; u++){
01486             for(int v=-this->axes[0]/2; v<this->axes[0]/2+y_extrapix; v++){
01487               index = (u+this->axes[1]/2)*this->axes[0]+v+this->axes[0]/2;
01488 
01489               diff_angle = 
01490                 -(relative_offsets[r][0]-relative_offsets[s][0])*facx*v + 
01491                 (relative_offsets[r][1]-relative_offsets[s][1])*facy*u;
01492 
01493               real_sum_exps = imag_sum_exps = 0;
01494               for(int k=0; k<npsfs; k++){
01495                 real_sum_exps += 
01496                   differential_amplitudes[k]*cos(relative_offsets[k][0]*facx*v+relative_offsets[k][1]*facy*u);
01497                 imag_sum_exps += 
01498                   differential_amplitudes[k]*sin(relative_offsets[k][0]*facx*v+relative_offsets[k][1]*facy*u);
01499               }
01500 
01501 
01502               tmp = psf_power[index]*cos(diff_angle);
01503               if(r==s){
01504                 
01505                 angle = -(relative_offsets[r][0]*facx*v + relative_offsets[r][1]*facy*u);
01506 
01507                 tmp2 = 
01508                   real_cross_product[index]*sin(angle) +
01509                   imag_cross_product[index]*cos(angle) +
01510                   psf_power[index]*(cos(angle)*imag_sum_exps +
01511                                     sin(angle)*real_sum_exps);
01512 
01513                 tmp3 = 
01514                   real_cross_product[index]*cos(angle)-
01515                   imag_cross_product[index]*sin(angle)+
01516                   psf_power[index]*(cos(angle)*real_sum_exps -
01517                                     sin(angle)*imag_sum_exps);
01518                   
01519                 
01520                 dchisq_dx[r] += differential_amplitudes[r]*v*differential_amplitudes[r]*tmp2;
01521                 dchisq_dy[r] += differential_amplitudes[r]*u*differential_amplitudes[r]*tmp2;
01522                 dchisq_db[r] += 
01523                   -(real_cross_product[index]*cos(angle)-
01524                   imag_cross_product[index]*sin(angle)) +
01525                   psf_power[index]*(cos(angle)*real_sum_exps -
01526                                     sin(angle)*imag_sum_exps);
01527                 
01528                 omega = 
01529                   differential_amplitudes[r]*differential_amplitudes[r]*psf_power[index] -
01530                   differential_amplitudes[r]*tmp3;
01531 
01532                 xi = tmp2;
01533 
01534               } else {
01535                 omega = differential_amplitudes[r]*differential_amplitudes[s]*tmp;
01536                 xi = differential_amplitudes[s]*psf_power[index]*sin(diff_angle);
01537               }
01538 
01539               // d^{2}chi^{2}/dx_{r}dx_{s}
01540               matrix[matrix_dimen*r+s] += v*v*omega;
01541               if(r!=s)
01542                 matrix[matrix_dimen*s+r] += v*v*omega;
01543 
01544               // d^{2}chi^{2}/dx_{r}dy_{s}
01545               matrix[matrix_dimen*r+s+npsfs] += u*v*omega;
01546               matrix[matrix_dimen*(s+npsfs)+r] += u*v*omega;
01547 
01548               // d^{2}chi^{2}/dx_{r}db_{s}
01549               matrix[matrix_dimen*r+s+2*npsfs] += v*xi;
01550               matrix[matrix_dimen*(s+2*npsfs)+r] += -v*xi;
01551 
01552               // d^{2}chi^{2}/dy_{r}dy_{s}
01553               matrix[matrix_dimen*(r+npsfs)+s+npsfs] += u*u*omega;
01554               if(r!=s)
01555                 matrix[matrix_dimen*(s+npsfs)+r+npsfs] += u*u*omega;
01556 
01557               // d^{2}chi^{2}/dy_{r}db_{s}
01558               matrix[matrix_dimen*(r+npsfs)+s+2*npsfs] += u*xi;
01559               matrix[matrix_dimen*(s+2*npsfs)+r+npsfs] += -u*xi;
01560 
01561               // d^{2}chi^{2}/db_{r}db_{s}
01562               matrix[matrix_dimen*(r+2*npsfs)+s+2*npsfs] += tmp;
01563               if(r!=s)
01564                 matrix[matrix_dimen*(s+2*npsfs)+r+2*npsfs] += tmp;
01565 
01566             }
01567           }
01568         }
01569       }
01570 
01571 
01572       vector<vector<double> > tmp_matrix(matrix_dimen);
01573       for(int r=0; r<matrix_dimen; r++){
01574         tmp_matrix[r].resize(matrix_dimen);
01575         for(int s=0; s<matrix_dimen; s++){
01576           tmp_matrix[r][s] = matrix[r*matrix_dimen+s];
01577         }
01578       }
01579 
01580 
01581 
01582       // Perform SVD    
01583       singular_value_decomposition<T>(jobu, 
01584                                       jobvt, 
01585                                       axes_0, 
01586                                       axes_1, 
01587                                       matrix,
01588                                       axes_0, 
01589                                       singular_values, 
01590                                       g_gtranspose_eigenmode_data, 
01591                                       axes_0, 
01592                                       gtranspose_g_eigenmode_data, 
01593                                       axes_1,
01594                                       work, 
01595                                       lwork, 
01596                                       info);
01597     
01598       /*
01599       if(pixel_array<T>::verbose_level){
01600         cout << "GGtrans\n";
01601         for(int r=0; r<matrix_dimen; r++){
01602           for(int s=0; s<matrix_dimen; s++){
01603             cout << setw(15) << g_gtranspose_eigenmode_data[r*matrix_dimen+s]; 
01604           }
01605           cout << endl;
01606         }
01607       }
01608 
01609       if(pixel_array<T>::verbose_level){
01610         cout << "Singular vals\n";
01611         for(int r=0; r<matrix_dimen; r++){
01612           cout << setw(15) << singular_values[r] << endl;
01613         }
01614       }
01615 
01616       if(pixel_array<T>::verbose_level){
01617         cout << "GtransG\n";
01618         for(int r=0; r<matrix_dimen; r++){
01619           for(int s=0; s<matrix_dimen; s++){
01620             cout << setw(15) << gtranspose_g_eigenmode_data[r*matrix_dimen+s]; 
01621           }
01622           cout << endl;
01623         }
01624       }
01625 
01626       if(pixel_array<T>::verbose_level){
01627         cout << "Reconstructed Matrix\n";
01628         for(int r=0; r<matrix_dimen; r++){
01629           for(int s=0; s<matrix_dimen; s++){
01630             tmp = 0;
01631             for(int k=0; k<matrix_dimen; k++){
01632               tmp += gtranspose_g_eigenmode_data[r*matrix_dimen+k]*
01633                 g_gtranspose_eigenmode_data[s+k*matrix_dimen]*singular_values[k];
01634               if(r==0 && s==0)
01635                 cout << " r==s==0 " 
01636                      << k 
01637                      << "\t" << gtranspose_g_eigenmode_data[r*matrix_dimen+k]
01638                      << "\t" << singular_values[k] 
01639                      << "\t" << g_gtranspose_eigenmode_data[s+k*matrix_dimen] 
01640                      << "\t" << tmp << endl;
01641             }
01642             cout << setw(15) << tmp;
01643           }
01644           cout << endl;
01645         }
01646       }
01647       */
01648 
01649       // Form the inverse from V S^{+} U^{T}
01650       for(int r=0; r<matrix_dimen; r++){
01651         for(int s=0; s<matrix_dimen; s++){
01652           tmp = 0;
01653           for(int k=0; k<matrix_dimen; k++){
01654             tmp += gtranspose_g_eigenmode_data[r*matrix_dimen+k]*
01655               g_gtranspose_eigenmode_data[s+k*matrix_dimen]/singular_values[k];
01656           }
01657           matrix[s*matrix_dimen+r]=tmp;
01658         }
01659       }
01660 
01661       if(pixel_array<T>::verbose_level){
01662         cout << "Identity\n";
01663         for(int r=0; r<matrix_dimen; r++){
01664           for(int s=0; s<matrix_dimen; s++){
01665             double tmp = 0;
01666             for(int t=0; t<matrix_dimen; t++)
01667               tmp += tmp_matrix[r][t]*matrix[t*matrix_dimen+s];
01668             cout << "\t" << tmp;
01669           }
01670           cout << endl;
01671         }
01672       }
01673 
01674       if(pixel_array<T>::verbose_level){
01675         cout << "Inverse\n";
01676         for(int r=0; r<matrix_dimen; r++){
01677           for(int s=0; s<matrix_dimen; s++){
01678             cout << setw(15) << matrix[r*matrix_dimen+s]; 
01679           }
01680           if(r<npsfs)
01681             cout << "\t\t" << dchisq_dx[r] << endl;
01682           else if(r>=npsfs && r<2*npsfs)
01683             cout << "\t\t" << dchisq_dy[r-npsfs] << endl;
01684           else
01685             cout << "\t\t" << dchisq_db[r-2*npsfs] << endl;
01686         }
01687       }
01688 
01689 
01690 
01691       // Multiply initial estimate by inverse
01692       for(int r=0; r<npsfs; r++){
01693         incr_differential_amplitudes[r] = 0;
01694         incr_relative_offsets[r][0] = 0;
01695         incr_relative_offsets[r][1] = 0;
01696         for(int s=0; s<npsfs; s++){
01697 
01698           incr_relative_offsets[r][0] += 
01699             matrix[matrix_dimen*r+s]*dchisq_dx[s] + 
01700             matrix[matrix_dimen*r+s+npsfs]*dchisq_dy[s] + 
01701             matrix[matrix_dimen*r+s+2*npsfs]*dchisq_db[s];
01702 
01703           incr_relative_offsets[r][1] += 
01704             matrix[matrix_dimen*(r+npsfs)+s]*dchisq_dx[s] + 
01705             matrix[matrix_dimen*(r+npsfs)+s+npsfs]*dchisq_dy[s] + 
01706             matrix[matrix_dimen*(r+npsfs)+s+2*npsfs]*dchisq_db[s];
01707 
01708           incr_differential_amplitudes[r] += 
01709             matrix[matrix_dimen*(r+2*npsfs)+s]*dchisq_dx[s] + 
01710             matrix[matrix_dimen*(r+2*npsfs)+s+npsfs]*dchisq_dy[s] + 
01711             matrix[matrix_dimen*(r+2*npsfs)+s+2*npsfs]*dchisq_db[s];
01712 
01713           /*
01714           incr_relative_offsets[r][0] += 
01715             matrix[matrix_dimen*s+r]*dchisq_dx[s] + 
01716             matrix[matrix_dimen*s+r+npsfs]*dchisq_dy[s] + 
01717             matrix[matrix_dimen*s+r+2*npsfs]*dchisq_db[s];
01718 
01719           incr_relative_offsets[r][1] += 
01720             matrix[matrix_dimen*(s+npsfs)+r]*dchisq_dx[s] + 
01721             matrix[matrix_dimen*(s+npsfs)+r+npsfs]*dchisq_dy[s] + 
01722             matrix[matrix_dimen*(s+npsfs)+r+2*npsfs]*dchisq_db[s];
01723 
01724           incr_differential_amplitudes[r] += 
01725             matrix[matrix_dimen*(s+2*npsfs)+r]*dchisq_dx[s] + 
01726             matrix[matrix_dimen*(s+2*npsfs)+r+npsfs]*dchisq_dy[s] + 
01727             matrix[matrix_dimen*(s+2*npsfs)+r+2*npsfs]*dchisq_db[s];
01728           */
01729 
01730         }
01731       }
01732 
01733       // Compute chi squared
01734       double real_arg=0, imag_arg=0;
01735       chisq = 0;
01736       for(int u=-this->axes[1]/2; u<this->axes[1]/2+x_extrapix; u++){
01737         for(int v=-this->axes[0]/2; v<this->axes[0]/2+y_extrapix; v++){
01738           index = (u+this->axes[1]/2)*this->axes[0]+v+this->axes[0]/2;
01739                 
01740           real = imag = 0;
01741           for(int k=0; k<npsfs; k++){
01742             angle = -(relative_offsets[k][0]*facx*v + relative_offsets[k][1]*facy*u);
01743             real += differential_amplitudes[k]*cos(angle);
01744             imag += differential_amplitudes[k]*sin(angle);
01745           }
01746           
01747           real_arg = this_arr[2*index] - psf_arr[2*index]*real + psf_arr[2*index+1]*imag;
01748           imag_arg = this_arr[2*index+1] - psf_arr[2*index+1]*real - psf_arr[2*index]*imag;
01749 
01750           chisq += .5*(real_arg*real_arg + imag_arg*imag_arg);
01751 
01752         }
01753       }
01754 
01755       if(pixel_array<T>::verbose_level)
01756         cout << " chisq " << chisq << "\t";
01757 
01758 
01759       // Increment estimates
01760       for(int r=0; r<npsfs; r++){
01761         relative_offsets[r][0] += incr_relative_offsets[r][0];
01762         relative_offsets[r][1] += incr_relative_offsets[r][1];
01763         differential_amplitudes[r] += incr_differential_amplitudes[r];
01764       }
01765 
01766       // Compute chi squared
01767       chisq = 0;
01768       for(int u=-this->axes[1]/2; u<this->axes[1]/2+x_extrapix; u++){
01769         for(int v=-this->axes[0]/2; v<this->axes[0]/2+y_extrapix; v++){
01770           index = (u+this->axes[1]/2)*this->axes[0]+v+this->axes[0]/2;
01771                 
01772           real = imag = 0;
01773           for(int k=0; k<npsfs; k++){
01774             angle = -(relative_offsets[k][0]*facx*v + relative_offsets[k][1]*facy*u);
01775             real += differential_amplitudes[k]*cos(angle);
01776             imag += differential_amplitudes[k]*sin(angle);
01777           }
01778           
01779           real_arg = this_arr[2*index] - psf_arr[2*index]*real + psf_arr[2*index+1]*imag;
01780           imag_arg = this_arr[2*index+1] - psf_arr[2*index+1]*real - psf_arr[2*index]*imag;
01781 
01782           chisq += .5*(real_arg*real_arg + imag_arg*imag_arg);
01783 
01784         }
01785       }
01786 
01787       if(pixel_array<T>::verbose_level){
01788         cout << " chisq " << chisq;
01789         for(int k=0; k<npsfs; k++)
01790           cout << " " << relative_offsets[k][0]
01791                << " " << incr_relative_offsets[k][0]
01792                << " " << relative_offsets[k][1]
01793                << " " << incr_relative_offsets[k][1]
01794                << " " << differential_amplitudes[k] 
01795                << " " << incr_differential_amplitudes[k];
01796         cout << endl;
01797       }
01798 
01799       if(chisq > last_chisq)
01800         break;
01801     }
01802 
01803     // Transform back to get residual from fit
01804     if(pixel_array<T>::verbose_level)
01805       cerr << "pixel_amp_array::fit - computing residuals\n";
01806 
01807     for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++){
01808       for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++){
01809         index = (i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2;
01810         real = imag = 0;
01811 
01812         for(int k=0; k<npsfs; k++){
01813 
01814           amp = sqrt(psf_arr[2*index]*psf_arr[2*index] + 
01815                      psf_arr[2*index+1]*psf_arr[2*index+1]);
01816           phase = atan2(psf_arr[2*index+1],psf_arr[2*index]);
01817 
01818           real += amp*cos(phase);
01819           imag += amp*sin(phase);
01820           
01821         }
01822         
01823         fit_arr[2*index] = real;
01824         fit_arr[2*index+1] = imag;
01825         
01826         this_arr[2*index] -= real;
01827         this_arr[2*index+1] -= imag;
01828       }
01829     }
01830 
01831 
01832     Arroyo::complex_cyclic_permutation(this->get_axes(), 
01833                                        -this->get_axes()[0]/2,
01834                                        -this->get_axes()[1]/2, 
01835                                        fit_arr);
01836     
01837     Arroyo::complex_cyclic_permutation(this->get_axes(), 
01838                                        -this->get_axes()[0]/2,
01839                                        -this->get_axes()[1]/2, 
01840                                        this_arr);
01841     
01842     fft_mgr.backward_fft(flipped_axes, false, true, fit_arr);
01843     fft_mgr.backward_fft(flipped_axes, false, true, this_arr);
01844 
01845     double norm_fac = 1/(double)(this->total_space());
01846     for(int i=0; i<nelem; i++){
01847       fit_arr[i] = fit_arr[2*i]*norm_fac;
01848       this_arr[i] = this_arr[2*i]*norm_fac;
01849     }
01850 
01851     fitted_model = pixel_array<T>(this->axes, fit_arr);
01852     fit_residual = pixel_array<T>(this->axes, this_arr);
01853 
01854     // Clean up
01855     if(pixel_array<T>::verbose_level)
01856       cerr << "pixel_amp_array::fit - cleaning up\n";
01857 
01858     // SVD stuff
01859     delete [] work;
01860     delete [] singular_values;
01861     delete [] gtranspose_g_eigenmode_data;
01862     delete [] g_gtranspose_eigenmode_data;
01863     delete [] matrix;
01864 
01865     delete [] this_arr;
01866     delete [] psf_arr;
01867     delete [] fit_arr;
01868     delete [] real_cross_product;
01869     delete [] imag_cross_product;
01870     delete [] psf_power;
01871 
01872     return(chisq);
01873   }
01874 
01875   template<class precision>
01876     double pixel_amp_array<precision>::aperture_photometry(
01877                                 double x, double y, 
01878                                 double inner_radius, double outer_radius) const {
01879 
01880     // Ensure that specified region lies within the image
01881     if(x < 0 || x > this->axes[1] || y < 0 || y > this->axes[0]){
01882       cerr << "pixel_amp_array::aperture_photometry error - coordinates "
01883            << x << ", " << y
01884            << " are out of range\n";
01885       this->print_axes(cerr);
01886       throw(std::string("pixel_amp_array::aperture_photometry"));
01887     }
01888 
01889     if(x-outer_radius < 0 || x+outer_radius > this->axes[1] ||
01890                         y-outer_radius < 0 || y + outer_radius > this->axes[0]){
01891       cerr << "pixel_amp_array::aperture_photometry error - coordinates "
01892            << x << ", " << y
01893            << " place an aperture of radius " << outer_radius << " out of range\n";
01894       this->print_axes(cerr);
01895       throw(std::string("pixel_amp_array::aperture_photometry"));
01896     }
01897 
01898     // Do the calculation
01899     double inner_flux = 0, outer_flux = 0;
01900     int inner_pixel_count = 0, outer_pixel_count = 0;
01901     int nelems = this->total_space();
01902     double distance;
01903     int axes_zero = this->axes[0];
01904     for(int i=0; i<nelems; i++){
01905       distance = sqrt((i/axes_zero-x)*(i/axes_zero-x) + 
01906                       (i%axes_zero-y)*(i%axes_zero-y)); 
01907       if(distance < inner_radius && this->pixelwts[i]!=0){
01908         inner_flux += this->pixeldata[i];
01909         inner_pixel_count++;
01910       } else if ((distance > inner_radius)
01911                         && (distance < outer_radius) && (this->pixelwts[i]!=0)) {
01912         outer_flux += this->pixeldata[i];
01913         outer_pixel_count++;
01914       }
01915     }
01916     
01917     outer_flux *= inner_pixel_count/(double)outer_pixel_count;
01918     inner_flux -= outer_flux;
01919     return(inner_flux);
01920   };
01921 
01922   template<class precision>
01923     template<class U>
01924     void pixel_amp_array<precision>::flag_outliers(
01925                         const pixel_amp_array<U> & pixamparr,
01926                         const double & threshold){
01927 
01928     if(!pixamparr.weights_allocated()){
01929       cerr << "pixel_amp_array::flag_outliers error - "
01930            << "reference array has no weights\n";
01931       throw(std::string("pixel_amp_array::flag_outliers"));
01932     }
01933 
01934     if(!this->weights_allocated()) this->allocate_weights(1);
01935 
01936     std::vector<long> paxes = pixamparr.get_axes();
01937     if(paxes.size()!=this->axes.size()){
01938       cerr << "pixel_amp_array<precision>::flag_outliers error - "
01939            << "mismatched number of axes\n";
01940       throw(std::string("pixel_amp_array<precision>::flag_outliers"));
01941     }
01942     for(int i=0; i<this->axes.size(); i++){
01943       if(paxes[i]!=this->axes[i]){
01944         cerr << "pixel_amp_array<precision>::flag_outliers error - "
01945              << "mismatched number of elements for axis "
01946              << i << "\t" << paxes[i] << "\t" << this->axes[i] << endl;
01947         throw(std::string("pixel_amp_array<precision>::flag_outliers"));
01948       }
01949     }
01950 
01951     int nelems = this->total_space();
01952     double diff;
01953     for(int i=0; i<nelems; i++){
01954       if(this->pixelwts[i]!=0 && pixamparr.wt(i)!=0){
01955         diff = this->pixeldata[i] - pixamparr.data(i);
01956         // Here we have 3 tests
01957         // The first tests whether a pixel in this array is much
01958         // greater than the one in the arg array
01959         // The second tests whether the pixel in this array
01960         // is much greater than the threshold.
01961         // The third tests whether the pixel in the arg array
01962         // is less than the threshold.
01963         // The last two test attempt to ensure that we are not
01964         // flagging points on the star itself.
01965         if(fabs(diff) > threshold && 
01966            this->pixeldata[i] > threshold && 
01967            pixamparr.data(i) < threshold){
01968           if(pixel_array<precision>::verbose_level)
01969             cout << "pixel_amp_array::flag_outliers - flagging point " 
01970                  << i/this->axes[0] << "," << i%this->axes[0] << "\t" 
01971                  << this->pixeldata[i] << "\t" << pixamparr.data(i) << endl;
01972           this->pixeldata[i] = 0;
01973           this->pixelwts[i] = 0;
01974         }
01975       }
01976     }
01977   }
01978 
01979   template<class precision>
01980     std::vector<float> pixel_amp_array<precision>::azav(int xcenter, int ycenter){
01981 
01982     if(this->axes.size()!=2){
01983       cerr << "pixel_array::decimate - cannot decimate "
01984            << "pixel_array with number of dimensions " 
01985            << this->axes.size() << endl;
01986       throw(std::string("pixel_array::decimate"));
01987     }
01988     if(xcenter<0 || xcenter>this->axes[0] || ycenter<0 || ycenter>this->axes[1]){
01989       cerr << "pixel_array::azav error - cannot average around point " 
01990            << xcenter << ", " << ycenter << endl;
01991       throw(std::string("pixel_array::azav"));
01992     }
01993 
01994     int radius;
01995     if(xcenter<this->axes[1]-xcenter) radius = xcenter;
01996     else radius = this->axes[1]-xcenter;
01997     if(ycenter<radius) radius = ycenter;
01998     if(this->axes[0]-ycenter<radius) radius = this->axes[0] - ycenter;
01999 
02000     std::vector<float> azave(radius, 0), real(radius, 0), imag(radius,0);
02001     
02002     double rad, irad;
02003     for(int i=0; i<this->axes[1]; i++){
02004       for(int j=0; j<this->axes[0]; j++){
02005         rad = sqrt((i-xcenter)*(i-xcenter) + (j-ycenter)*(j-ycenter));
02006         irad = (int)(rad + .5);
02007         if(irad>=radius) continue;
02008         if(this->weights_allocated()){
02009           if(this->pixelwts[i*(this->axes[0])+j] != 0){
02010             real[irad] += cos((double)(this->pixeldata[i*(this->axes[0])+j]));
02011             imag[irad] += sin((double)(this->pixeldata[i*(this->axes[0])+j]));
02012           }
02013         } else {
02014           real[irad] += cos((double)(this->pixeldata[i*(this->axes[0])+j]));
02015           imag[irad] += sin((double)(this->pixeldata[i*(this->axes[0])+j]));
02016         }         
02017       }
02018     }
02019     
02020     for(int i=0; i<azave.size(); i++)
02021       azave[i] = atan2(imag[i],real[i]);
02022 
02023     return(azave);
02024   }
02025 
02026   template <class precision>
02027     pixel_amp_array<precision> operator + (const pixel_amp_array<precision> &p1,
02028                                         const pixel_amp_array<precision> &p2){
02029     if(p1.get_axes()!=p2.get_axes()){
02030       cerr << "pixel_amp_array<precision>::operator+ error - " 
02031            << "mismatched array sizes:\n";
02032       throw(std::string("pixel_amp_array<precision>::operator+"));
02033     }
02034     pixel_amp_array<precision> pixamparr(p1);
02035     pixamparr += p2;
02036     return(pixamparr);
02037   }
02038 
02039   template <class precision>
02040     pixel_amp_array<precision> operator - (const pixel_amp_array<precision> &p1,
02041                                         const pixel_amp_array<precision> &p2){
02042     if(p1.get_axes()!=p2.get_axes()){
02043       cerr << "pixel_amp_array<precision>::operator- error - " 
02044            << "mismatched array sizes:\n";
02045       throw(std::string("pixel_amp_array<precision>::operator-"));
02046     }
02047     pixel_amp_array<precision> pixamparr(p1);
02048     pixamparr -= p2;
02049     return(pixamparr);
02050   }
02051 
02052   template <class precision>
02053     pixel_amp_array<precision> operator * (const pixel_amp_array<precision> &p1,
02054                                         const pixel_amp_array<precision> &p2){
02055     if(p1.get_axes()!=p2.get_axes()){
02056       cerr << "pixel_amp_array<precision>::operator* error - " 
02057            << "mismatched array sizes:\n";
02058       throw(std::string("pixel_amp_array<precision>::operator/"));
02059     }
02060     pixel_amp_array<precision> pixamparr(p1);
02061     pixamparr *= p2;
02062     return(pixamparr);
02063   }
02064 
02065   template <class precision>
02066     pixel_amp_array<precision> operator / (const pixel_amp_array<precision> &p1,
02067                                         const pixel_amp_array<precision> &p2){
02068     if(p1.get_axes()!=p2.get_axes()){
02069       cerr << "pixel_amp_array<precision>::operator/ error - " 
02070            << "mismatched array sizes:\n";
02071       throw(std::string("pixel_amp_array<precision>::operator/"));
02072     }
02073     pixel_amp_array<precision> pixamparr(p1);
02074     pixamparr /= p2;
02075     return(pixamparr);
02076   }
02077 
02078   template <class precision>
02079     pixel_amp_array<precision> operator + (const pixel_amp_array<precision> &p1, double & fac){
02080     pixel_amp_array<precision> pixamparr(p1);
02081     pixamparr += fac;
02082     return(pixamparr);
02083   }
02084 
02085   template <class precision>
02086     pixel_amp_array<precision> operator - (const pixel_amp_array<precision> &p1, double & fac){
02087     pixel_amp_array<precision> pixamparr(p1);
02088     pixamparr -= fac;
02089     return(pixamparr);
02090   }
02091 
02092   template <class precision>
02093     pixel_amp_array<precision> operator * (const pixel_amp_array<precision> &p1, double & fac){
02094     pixel_amp_array<precision> pixamparr(p1);
02095     pixamparr *= fac;
02096     return(pixamparr);
02097   }
02098 
02099   template <class precision>
02100     pixel_amp_array<precision> operator / (const pixel_amp_array<precision> &p1, double & fac){
02101     pixel_amp_array<precision> pixamparr(p1);
02102     pixamparr /= fac;
02103     return(pixamparr);
02104   }
02105 
02108   template<class precision>
02109     bool operator != (const pixel_amp_array<precision> &p1, const pixel_amp_array<precision> &p2){
02110     return(!(p1==p2));
02111   }
02112 
02113 }
02114 
02115 #endif

Generated on Thu Nov 29 17:16:30 2007 for arroyo by  doxygen 1.3.9.1