00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
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
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
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
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
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
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
00731
00732
00733
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
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
00761
00762
00763
00764
00765
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
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
00810
00811
00812
00813
00814
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
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
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
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
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
01123
01124
01125
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
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
01153
01154
01155
01156
01157
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
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
01195
01196
01197
01198
01199
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
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
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
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
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
01540 matrix[matrix_dimen*r+s] += v*v*omega;
01541 if(r!=s)
01542 matrix[matrix_dimen*s+r] += v*v*omega;
01543
01544
01545 matrix[matrix_dimen*r+s+npsfs] += u*v*omega;
01546 matrix[matrix_dimen*(s+npsfs)+r] += u*v*omega;
01547
01548
01549 matrix[matrix_dimen*r+s+2*npsfs] += v*xi;
01550 matrix[matrix_dimen*(s+2*npsfs)+r] += -v*xi;
01551
01552
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
01558 matrix[matrix_dimen*(r+npsfs)+s+2*npsfs] += u*xi;
01559 matrix[matrix_dimen*(s+2*npsfs)+r+npsfs] += -u*xi;
01560
01561
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
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
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
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
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
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730 }
01731 }
01732
01733
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
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
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
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
01855 if(pixel_array<T>::verbose_level)
01856 cerr << "pixel_amp_array::fit - cleaning up\n";
01857
01858
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
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
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
01957
01958
01959
01960
01961
01962
01963
01964
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