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

diffractive_wavefront.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 DIFFRACTIVE_WAVEFRONT_H
00032 #define DIFFRACTIVE_WAVEFRONT_H
00033 
00034 #include <complex>
00035 #include <fstream>
00036 #include <colormap.h>
00037 #include <fft_manager.h>
00038 #include <pixel_amp_array.h>
00039 #include <pixel_phase_array.h>
00040 #include "sim_utils.h"
00041 #include "wavefront.h"
00042 
00043 namespace Arroyo {
00044 
00045   using std::string;
00046   using std::vector;
00047   using std::ostream;
00048   using std::cerr;
00049   using std::endl;
00050 
00051   /* forward declarations */
00052   template <class T> class diffractive_wavefront;
00053   template <class T> bool operator == (const diffractive_wavefront<T> &p1, const diffractive_wavefront<T> &p2);
00054   template <class T> bool operator != (const diffractive_wavefront<T> &p1, const diffractive_wavefront<T> &p2);
00055   class optic;
00056 
00060 
00061   template <class T>
00062     class diffractive_wavefront : 
00063     virtual public wavefront,
00064     virtual public diffractive_wavefront_header<T>, 
00065     protected fft_manager<T> {
00066 
00067     private:
00068 
00075     friend class one_to_one_optic;
00076 
00083     friend class one_to_many_optic;
00084 
00087     template<class U>
00088       void multiply(const pixel_amp_array<U> & pixamparr);
00089 
00092     template<class U>  
00093       void add(const pixel_phase_array<U> & pixpharr);
00094 
00095     protected:
00096 
00098     mutable T * wfdata;  
00099 
00108   
00110     mutable bool real_imag;
00111 
00113     mutable bool interleaved;
00114 
00118     void real_imag_conversion() const ;
00119   
00123     void amp_phase_conversion() const ;
00124 
00134     void interleaved_conversion() const;
00135 
00145     void non_interleaved_conversion() const;
00146 
00147     private:
00148 
00149     static const bool factory_registration;
00150 
00155     void cyclic_permutation(long xshift, long yshift) const;
00156 
00170     void near_field_propagator(double distance, bool fresnel);
00171   
00196     void far_field_propagator(double distance, bool fresnel,
00197                               double final_pixel_scale=-1,
00198                               vector<long> final_axes = vector<long>());
00199 
00205     void update_timestamp(double dist) {timestamp += dist/299792458;};
00206 
00214     void forward_fft();
00215 
00223     void backward_fft();
00224   
00225     public:
00226 
00229     diffractive_wavefront();
00230 
00233     diffractive_wavefront(const diffractive_wavefront<T> & dwf);
00234 
00237     diffractive_wavefront(const char * filename);
00238 
00241     diffractive_wavefront(const iofits & iof);
00242 
00245     diffractive_wavefront(const diffractive_wavefront_header<T> & dwfh, T * data = NULL, 
00246                           bool rl_img = true, bool intrlvd = true);
00247 
00250     ~diffractive_wavefront();
00251 
00254     diffractive_wavefront & operator=(const diffractive_wavefront<T> & dwf);
00255 
00258     void resize(const vector<long> & axes);
00259 
00263     void mask();
00264 
00267     template<class U>
00268       void install(const pixel_amp_array<U> & pixamparr);
00269 
00272     template<class U>
00273       void install(const pixel_phase_array<U> & pixpharr);
00274 
00277     pixel_amp_array<T> extract_amps() const;
00278 
00281     pixel_phase_array<T> extract_phases() const;
00282 
00286     void wrap_phases(){
00287       // Optimize later
00288       pixel_phase_array<T> pixpharr = this->extract_phases();
00289       pixpharr.wrap();
00290       this->install(pixpharr);
00291     };
00292 
00296 
00299     void read(const char * filename);
00300 
00303     void read(const iofits & iof);
00304 
00320     void write(const char * filename) const;
00321 
00333     void write(iofits & iof) const;
00334 
00348     void write_amps_to_ppm(double min, double max, 
00349                            bool logscale, 
00350                            bool colorbar, 
00351                            colormap * cmap, 
00352                            const char * filename, 
00353                            long min_dimen=-1) const;
00354 
00368     void write_phases_to_ppm(double min, double max, 
00369                              bool colorbar, 
00370                              colormap * cmap, 
00371                              const char * filename, 
00372                              long min_dimen=-1) const;
00373 
00376     void print(ostream & os, const char * prefix) const;
00377 
00386     std::complex<T> data(int n) const;
00387 
00396     void set_data(int n, std::complex<T> & dat);
00397 
00404     void set_propagation_direction(const three_vector & prop_dir);
00405 
00409     void set_wavefront_curvature(double curvature);
00410 
00435     void exact_propagator(double distance, double final_pixel_scale=-1, 
00436                           vector<long> final_axes=vector<long>());
00437 
00438 
00444     void geometric_propagator(double distance);
00445 
00459     void near_field_angular_propagator(double distance);
00460 
00477     void near_field_fresnel_propagator(double distance);
00478 
00490     void far_field_fresnel_propagator(double distance);
00491 
00504     void far_field_fraunhoffer_propagator(double distance);
00505 
00526     void far_field_fresnel_goertzel_reinsch_propagator(double distance, 
00527                                                        double final_pixel_scale, 
00528                                                        vector<long> final_axes);
00529 
00550     void far_field_fraunhoffer_goertzel_reinsch_propagator(double distance, 
00551                                                            double final_pixel_scale, 
00552                                                            vector<long> final_axes);
00553 
00560     void finite_difference_method_propagator(double distance);
00561 
00568     void rotate(double angle);
00569 
00572     double total_power() const;
00573 
00577     template<class U>
00578       void pad_array(int npad, std::complex<U> value);
00579 
00582     void clip_array(int nclip);
00583   
00586     template<class U, class V> 
00587       friend diffractive_wavefront<U> & operator+=(diffractive_wavefront<U> & lhs_dwf, const diffractive_wavefront<V> & rhs_dwf);
00588 
00591     template<class U, class V> 
00592       friend diffractive_wavefront<U> & operator-=(diffractive_wavefront<U> & lhs_dwf, const diffractive_wavefront<V> & rhs_dwf);
00593 
00596     template<class U, class V>  
00597       friend diffractive_wavefront<U> & operator*=(diffractive_wavefront<U> & lhs_dwf, const diffractive_wavefront<V> & rhs_dwf);
00598 
00601     template<class U, class V>
00602       friend diffractive_wavefront<U> & operator/=(diffractive_wavefront<U> & lhs_dwf, const diffractive_wavefront<V> & rhs_dwf);
00603 
00606     template<class U>
00607       diffractive_wavefront<T> & operator +=(std::complex<U> c);
00608 
00611     template<class U>
00612       diffractive_wavefront<T> & operator -=(std::complex<U> c);
00613 
00616     template<class U>
00617       diffractive_wavefront<T> & operator *=(std::complex<U> c);
00618 
00621     template<class U>
00622       diffractive_wavefront<T> & operator /=(std::complex<U> c);
00623 
00626     friend bool operator ==(const diffractive_wavefront<T> & dwf1, const diffractive_wavefront<T> & dwf2) {
00627       if(operator!=(static_cast<const diffractive_wavefront_header<T> >(dwf1), 
00628                     static_cast<const diffractive_wavefront_header<T> >(dwf2)))
00629         return(false);
00630       int nelem = dwf1.total_space();
00631       for(int i=0; i<nelem; i++)
00632         if(dwf1.wfdata[i]!=dwf2.wfdata[i]) return(false);
00633       return(true);
00634     };
00635 
00636   };
00637 
00638 
00639   template<class T>
00640     void diffractive_wavefront<T>::resize(const vector<long> & in_axes) {
00641 
00642     if(in_axes.size()!=2){
00643       cerr << "diffractive_wavefront::resize error - axes argument does not have 2 dimensions\n";
00644       throw(string("diffractive_wavefront::resize"));
00645     }
00646     int nelem = 1;
00647     for(int i=0; i<in_axes.size(); i++) {
00648       if(in_axes[i]<0){
00649         cerr << "diffractive_wavefront::resize error - cannot resize using an axis dimension " << in_axes[i] 
00650              << " less than or equal to zero\n";
00651         throw(string("diffractive_wavefront::resize"));
00652       }
00653       nelem *= in_axes[i];
00654     }
00655 
00656     if(nelem != this->diffractive_wavefront_header<T>::total_space()){
00657       if(wavefront::verbose_level>1){
00658         cerr << "diffractive_wavefront::resize - resizing diffractive_wavefront from "
00659              << this->axes[0] << "x" << this->axes[1] << " to " 
00660              << in_axes[0] << "x" << in_axes[1] 
00661              << " for a total of " << nelem << " elements\n";
00662       }
00663 
00664       if(wfdata!=NULL) delete [] wfdata;
00665       try{wfdata = new T[2*nelem];}
00666       catch(...) {
00667         cerr << "diffractive_wavefront::resize - unable to allocate memory\n";
00668         throw(string("diffractive_wavefront::resize"));
00669       }
00670     }
00671  
00672     int tmp = 2*nelem;
00673     for(int i=0; i<tmp; i++) 
00674       wfdata[i] = 0;
00675 
00676     this->axes = in_axes;
00677   }
00678 
00679   template<class T>
00680     void diffractive_wavefront<T>::cyclic_permutation(long xshift, long yshift) const {
00681     this->interleaved_conversion(); 
00682     Arroyo::complex_cyclic_permutation(this->axes, xshift, yshift, wfdata);
00683   }
00684 
00685   template<class T>
00686     void diffractive_wavefront<T>::real_imag_conversion() const {
00687   
00688     if(real_imag) return;
00689 
00690     int nelem = this->diffractive_wavefront_header<T>::total_space();
00691     int index;
00692     T tmpamp, tmpphase;
00693     if(interleaved){
00694       for(int i=0; i<nelem; i++){
00695         index = 2*i;
00696         tmpamp = wfdata[index];
00697         tmpphase = wfdata[index+1];
00698         wfdata[index] = tmpamp * cos(tmpphase);
00699         wfdata[index+1] = tmpamp * sin(tmpphase);
00700       }
00701     } else {
00702       for(int i=0; i<nelem; i++){
00703         tmpamp = wfdata[i];
00704         tmpphase = wfdata[i+nelem];
00705         wfdata[i] = tmpamp * cos(tmpphase);
00706         wfdata[i+nelem] = tmpamp * sin(tmpphase);
00707       }
00708     }
00709 
00710     real_imag = true;
00711   }
00712  
00713   template<class T>
00714     void diffractive_wavefront<T>::amp_phase_conversion() const {
00715 
00716     if(!real_imag) return;
00717 
00718     int nelem = this->diffractive_wavefront_header<T>::total_space();
00719     int index;
00720     T tmpreal, tmpimag;
00721     if(interleaved){
00722       for(int i=0; i<nelem; i++){
00723         index = 2*i;
00724         tmpreal = wfdata[index];
00725         tmpimag = wfdata[index+1];
00726         wfdata[index] = sqrt(tmpreal*tmpreal + tmpimag*tmpimag);
00727         wfdata[index+1] = atan2(tmpimag,tmpreal);
00728       }
00729     } else {
00730       for(int i=0; i<nelem; i++){
00731         tmpreal = wfdata[i];
00732         tmpimag = wfdata[i+nelem];
00733         wfdata[i] = sqrt(tmpreal*tmpreal + tmpimag*tmpimag);
00734         wfdata[i+nelem] = atan2(tmpimag,tmpreal);
00735       }
00736     }
00737 
00738     real_imag = false;
00739   }
00740 
00741   template<class T>
00742     void diffractive_wavefront<T>::interleaved_conversion() const {
00743 
00744     // here we put wfdata[i] => wfdata[2*i]
00745     // and wfdata[i+nelem] => wfdata[2*i+1]
00746 
00747     if(interleaved) return;
00748 
00749     int nelem = diffractive_wavefront_header<T>::total_space();
00750     T * tmp;
00751 
00752     try{tmp=new T[2*nelem];}
00753     catch(...){
00754       cerr << "diffractive_wavefront::interleaved_conversion error - "
00755            << "unable to allocate memory\n";
00756       throw(string("diffractive_wavefront::interleaved_conversion"));
00757     }
00758 
00759     memcpy(tmp, wfdata, sizeof(T)*nelem*2);
00760     for(int i=0; i<nelem; i++){
00761       wfdata[2*i] = tmp[i];
00762       wfdata[2*i+1] = tmp[i+nelem];
00763     }
00764 
00765     interleaved = true;
00766     delete [] tmp;
00767   }
00768 
00769   template<class T>
00770     void diffractive_wavefront<T>::non_interleaved_conversion() const {
00771 
00772     // here we put wfdata[2*i] => wfdata[i]
00773     // and wfdata[2*i+1] => wfdata[i+nelem]
00774 
00775     if(!interleaved) return;
00776 
00777     int nelem = diffractive_wavefront_header<T>::total_space();
00778     T * tmp;
00779 
00780     try{tmp= new T[nelem];}
00781     catch(...){
00782       cerr << "diffractive_wavefront::non_interleaved_conversion error - "
00783            << "unable to allocate memory\n";
00784       throw(string("diffractive_wavefront::non_interleaved_conversion"));
00785     }
00786 
00787     for(int i=0; i<nelem; i++)
00788       tmp[i] = wfdata[2*i+1];
00789   
00790     for(int i=0; i<nelem; i++)
00791       wfdata[i] = wfdata[2*i];
00792 
00793     for(int i=0; i<nelem; i++)
00794       wfdata[i+nelem] = tmp[i];
00795 
00796     interleaved = false;
00797     delete [] tmp;
00798   }
00799   
00800  template<class T>
00801     diffractive_wavefront<T>::diffractive_wavefront(){
00802     wfdata = NULL;
00803     real_imag = true;
00804     interleaved = true;
00805   }
00806 
00807   template<class T>
00808     diffractive_wavefront<T>::diffractive_wavefront(const diffractive_wavefront<T> & dwf){
00809     wfdata = NULL;
00810     this->operator=(dwf);
00811   }
00812 
00813   template<class T>
00814     diffractive_wavefront<T>::diffractive_wavefront(const char * filename){
00815     wfdata = NULL;
00816     interleaved = false;
00817     this->read(filename);
00818   }
00819 
00820   template<class T>
00821     diffractive_wavefront<T>::diffractive_wavefront(const iofits & iof){
00822 
00823     wfdata = NULL;
00824     interleaved = false;
00825     this->read(iof);
00826   }
00827 
00828   template<class T>
00829     diffractive_wavefront<T>::diffractive_wavefront(const diffractive_wavefront_header<T> & dwfh, 
00830                                                     T * data, bool rl_img, bool intrlvd) {
00831 
00832     real_imag = rl_img;
00833     interleaved = intrlvd;
00834 
00835     wfdata = NULL;
00836     vector<long> tmp = dwfh.get_axes();
00837     this->resize(dwfh.get_axes());
00838     if(data!=NULL){
00839       int nelem = 2*dwfh.get_axes()[0]*dwfh.get_axes()[1];
00840       for(int i=0; i<nelem; i++) wfdata[i] = data[i];
00841     }
00842     this->diffractive_wavefront_header<T>::operator=(dwfh);
00843   }
00844 
00845   template<class T>
00846     diffractive_wavefront<T>::~diffractive_wavefront(){
00847     delete [] wfdata;
00848   }
00849 
00850   template<class T>
00851     diffractive_wavefront<T> & diffractive_wavefront<T>::operator=(const diffractive_wavefront<T> & dwf){
00852 
00853     if(this==&dwf)
00854       return(*this);
00855 
00856     real_imag = dwf.real_imag;
00857     interleaved = dwf.interleaved;
00858     if(this->diffractive_wavefront_header<T>::total_space()!=dwf.diffractive_wavefront_header<T>::total_space())
00859       this->resize(dwf.get_axes());
00860 
00861     int nelem = dwf.diffractive_wavefront_header<T>::total_space();
00862     for(int i=0; i<2*nelem; i++)
00863       wfdata[i] = dwf.wfdata[i];
00864 
00865     this->diffractive_wavefront_header<T>::operator=(dwf); 
00866     this->fft_manager<T>::operator=(dwf);
00867     return(*this);
00868   }
00869 
00870   template<class T>
00871     void diffractive_wavefront<T>::mask(){
00872  
00873     int nelem = diffractive_wavefront_header<T>::total_space();
00874     if(interleaved){
00875       for(int i=0; i<nelem; i++)
00876         if(wfdata[2*i]==0) wfdata[2*i+1] = 0;
00877     } else {
00878       for(int i=0; i<nelem; i++)
00879         if(wfdata[i]==0) wfdata[i+nelem] = 0;
00880     }
00881   }
00882 
00883   template<class T>
00884     template<class U>
00885     void diffractive_wavefront<T>::install(const pixel_amp_array<U> & pixamparr){
00886 
00887     int nelem = diffractive_wavefront_header<T>::total_space();
00888     if(diffractive_wavefront_header<T>::axes!=pixamparr.get_axes()){
00889       cerr << "diffractive_wavefront::install error - " 
00890            << "mismatched axes\n";
00891       cerr << "diffractive wavefront axes " << this->axes[0] << ", " << this->axes[1] << endl;
00892       cerr << "pixel amp array axes " << pixamparr.get_axes()[0] << ", " << pixamparr.get_axes()[1] << endl;
00893       throw(string("diffractive_wavefront::install"));
00894     }
00895 
00896     this->amp_phase_conversion();
00897 
00898     if(interleaved){
00899       for(int i=0; i<nelem; i++)
00900         wfdata[2*i] = pixamparr.data(i);
00901     } else {
00902       for(int i=0; i<nelem; i++)
00903         wfdata[i] = pixamparr.data(i);
00904     }
00905   }
00906 
00907   template<class T>
00908     template<class U>
00909     void diffractive_wavefront<T>::install(const pixel_phase_array<U> & pixpharr){
00910 
00911     int nelem = diffractive_wavefront_header<T>::total_space();
00912     if(diffractive_wavefront_header<T>::axes!=pixpharr.get_axes()){
00913       cerr << "diffractive_wavefront::install error - " 
00914            << "mismatched axes\n";
00915       cerr << "diffractive wavefront axes " << this->axes[0] << ", " << this->axes[1] << endl;
00916       cerr << "pixel phase array axes " << pixpharr.get_axes()[0] << ", " << pixpharr.get_axes()[1] << endl;
00917       throw(string("diffractive_wavefront::install"));
00918     }
00919 
00920     this->amp_phase_conversion();
00921 
00922     if(interleaved){
00923       for(int i=0; i<nelem; i++) {
00924         if(wfdata[2*i]==0) wfdata[2*i+1]=0;
00925         else wfdata[2*i+1] = pixpharr.data(i);
00926       }
00927     } else {
00928       for(int i=0; i<nelem; i++){
00929         if(wfdata[i]==0) wfdata[i+nelem]=0;
00930         else wfdata[i+nelem] = pixpharr.data(i);
00931       }
00932     }
00933   }
00934 
00935   template<class T>
00936     pixel_amp_array<T> diffractive_wavefront<T>::extract_amps() const {
00937 
00938     int nelem = this->diffractive_wavefront_header<T>::total_space();
00939     T * amps;
00940     try{amps = new T[nelem];}
00941     catch(...){
00942       cerr << "diffractive_wavefront::extract_amps error - "
00943            << "unable to allocate memory\n";
00944       throw(string("diffractive_wavefront::extract_amps"));
00945     }
00946     this->amp_phase_conversion();
00947 
00948     if(interleaved){
00949       for(int i=0; i<nelem; i++)
00950         amps[i] = wfdata[2*i];
00951     } else {
00952       for(int i=0; i<nelem; i++)
00953         amps[i] = wfdata[i];
00954     }
00955 
00956     pixel_amp_array<T> pixamparr(this->diffractive_wavefront_header<T>::axes, amps);
00957     delete [] amps;
00958     return(pixamparr);
00959   }
00960 
00961   template<class T>
00962     pixel_phase_array<T> diffractive_wavefront<T>::extract_phases() const {
00963 
00964     int nelem = this->diffractive_wavefront_header<T>::total_space();
00965     T * phases;
00966     try{phases = new T[nelem];}
00967     catch(...){
00968       cerr << "diffractive_wavefront::extract_phases error - "
00969            << "unable to allocate memory\n";
00970       throw(string("diffractive_wavefront::extract_phases"));
00971     }
00972 
00973     this->amp_phase_conversion();
00974 
00975     if(interleaved){
00976       for(int i=0; i<nelem; i++)
00977         phases[i] = wfdata[2*i+1];
00978     } else {
00979       for(int i=0; i<nelem; i++)
00980         phases[i] = wfdata[i+nelem];
00981     }
00982 
00983     pixel_phase_array<T> pixpharr(this->diffractive_wavefront_header<T>::axes, phases);
00984     delete [] phases;
00985     return(pixpharr);
00986   }
00987 
00988   template<class T>
00989     template<class U>
00990     void diffractive_wavefront<T>::multiply(const pixel_amp_array<U> & pixamparr) {
00991 
00992     int nelem = diffractive_wavefront_header<T>::total_space();
00993     if(diffractive_wavefront_header<T>::axes!=pixamparr.get_axes()){
00994       cerr << "diffractive_wavefront::multiply error - " 
00995            << "mismatched axes\n";
00996       throw(string("diffractive_wavefront::multiply"));
00997     }
00998 
00999     this->amp_phase_conversion();
01000 
01001     if(interleaved){
01002       for(int i=0; i<nelem; i++) 
01003         wfdata[2*i] *= pixamparr.data(i);
01004     } else {
01005       for(int i=0; i<nelem; i++)
01006         wfdata[i] *= pixamparr.data(i);
01007     }
01008   }
01009 
01010   template<class T>
01011     template<class U>
01012     void diffractive_wavefront<T>::add(const pixel_phase_array<U> & pixpharr) {
01013 
01014     int nelem = diffractive_wavefront_header<T>::total_space();
01015     if(diffractive_wavefront_header<T>::axes!=pixpharr.get_axes()){
01016       cerr << "diffractive_wavefront::add error - " 
01017            << "mismatched axes\n";
01018       throw(string("diffractive_wavefront::add"));
01019     }
01020 
01021     this->amp_phase_conversion();
01022 
01023     if(interleaved){
01024       for(int i=0; i<nelem; i++) {
01025         if(wfdata[2*i]==0) wfdata[2*i+1]=0;
01026         else wfdata[2*i+1] += pixpharr.data(i);
01027       }
01028     } else {
01029       for(int i=0; i<nelem; i++){
01030         if(wfdata[i]==0) wfdata[i+nelem]=0;
01031         else wfdata[i+nelem] += pixpharr.data(i);
01032       }
01033     }
01034   }
01035 
01036   template<class T>
01037     void diffractive_wavefront<T>::read(const char * filename) {
01038     iofits iof;
01039     try{iof.open(filename);}
01040     catch(...){
01041       cerr << "diffractive_wavefront::read - "
01042            << "error opening file " << filename << endl;
01043       throw(string("diffractive_wavefront::read"));
01044     }
01045     try{this->read(iof);}
01046     catch(...){
01047       cerr << "diffractive_wavefront::read - "
01048            << "error reading diffractive wavefront from file " 
01049            << filename << endl;
01050       throw(string("diffractive_wavefront::read"));
01051     }
01052   }
01053 
01054   template<class T>
01055     void diffractive_wavefront<T>::read(const iofits & iof) {
01056 
01057     // read into temporary header
01058     // since resize uses the data
01059     // residing in the diffractive_wavefront_header
01060     diffractive_wavefront_header<T> wfhdr(iof);
01061     this->resize(wfhdr.get_axes());
01062     this->operator=(wfhdr);
01063   
01064     if(wavefront::verbose_level>1)
01065       cout << "diffractive_wavefront::read - reading amplitudes\n";
01066     pixel_amp_array<T> pixamparr(iof);
01067     this->install(pixamparr);
01068 
01069     if(wavefront::verbose_level>1)
01070       cout << "diffractive_wavefront::read - reading phases\n";
01071     pixel_phase_array<T> pixpharr(iof);
01072     this->install(pixpharr);
01073 
01074   }
01075 
01076   template<class T>
01077     void diffractive_wavefront<T>::write(const char * filename) const {
01078     iofits iof;
01079     try{iof.create(filename);}
01080     catch(...){
01081       cerr << "diffractive_wavefront::write - "
01082            << "error opening file " << filename << endl;
01083       throw(string("diffractive_wavefront::write"));
01084     }
01085     try{this->write(iof);}
01086     catch(...){
01087       cerr << "diffractive_wavefront::write - "
01088            << "error writing diffractive wavefront to file " 
01089            << filename << endl;
01090       iof.print_header(cerr, "error");
01091       throw(string("diffractive_wavefront::write"));
01092     }
01093   }
01094 
01095   template<class T>
01096     void diffractive_wavefront<T>::write(iofits & iof) const {
01097 
01098     try{this->diffractive_wavefront_header<T>::write(iof);}
01099     catch(...){
01100       cerr << "diffractive_wavefront::write error - could not write header\n";
01101       throw(string("diffractive_wavefront::write"));
01102     }
01103 
01104     try{this->extract_amps().write(iof);}
01105     catch(...){
01106       cerr << "diffractive_wavefront::write error - could not write amps\n";
01107       throw(string("diffractive_wavefront::write"));
01108     }
01109     
01110 
01111     // Here we have to start a new hdu, since 
01112     // pixel_array will not start one for us
01113     fits_header_data<T> fhd(this->get_axes());
01114     fhd.write(iof);
01115 
01116     try{this->extract_phases().write(iof);}
01117     catch(...){
01118       cerr << "diffractive_wavefront::write error - could not write phases\n";
01119       throw(string("diffractive_wavefront::write"));
01120     }
01121   }
01122 
01123   template<class T> 
01124     void diffractive_wavefront<T>::print(ostream & os, const char * prefix) const {
01125     this->diffractive_wavefront_header<T>::print(os, prefix); 
01126   }
01127 
01128   template<class T>
01129     std::complex<T> diffractive_wavefront<T>::data(int n) const {
01130 
01131     if(n<0 || n>=this->diffractive_wavefront_header<T>::total_space()){
01132       cerr << "diffractive_wavefront<T>::data error - index " << n 
01133            << " supplied to this function is out of range 0 - "
01134            << this->diffractive_wavefront_header<T>::total_space()-1 << endl;
01135       throw(string("diffractive_wavefront<T>::data"));
01136     }
01137 
01138     // NOTE:  NEED TO FIX THIS UP TO ACCOUNT FOR CURVATURE, IF PRESENT
01139     // CHANGE angle definitions below to add curvature term
01140 
01141     std::complex<T> c;
01142     if(real_imag && interleaved) {
01143       c = std::complex<T>(wfdata[2*n], wfdata[2*n+1]);
01144     } else if(real_imag && !interleaved) {
01145       c = std::complex<T>(wfdata[n], wfdata[n+this->diffractive_wavefront_header<T>::total_space()]);
01146     } else if(!real_imag && interleaved) {
01147       double tmp = wfdata[2*n];
01148       double angle = wfdata[2*n+1];
01149       c = std::complex<T>(tmp*cos(angle), tmp*sin(angle));
01150     } else if(!real_imag && !interleaved) {
01151       double tmp = wfdata[n];
01152       double angle = wfdata[n+this->diffractive_wavefront_header<T>::total_space()];
01153       c = std::complex<T>(tmp*cos(angle), tmp*sin(angle));
01154     }
01155   
01156     return(c);
01157   }
01158 
01159   template<class T>
01160     void diffractive_wavefront<T>::set_data(int n, std::complex<T> & dat) {
01161 
01162     if(n<0 || n>=this->diffractive_wavefront_header<T>::total_space()){
01163       cerr << "diffractive_wavefront<T>::set_data error - index " << n 
01164            << " supplied to this function is out of range 0 - "
01165            << this->diffractive_wavefront_header<T>::total_space()-1 << endl;
01166       throw(string("diffractive_wavefront<T>::set_data"));
01167     }
01168 
01169     // NOTE:  NEED TO FIX THIS UP TO ACCOUNT FOR CURVATURE, IF PRESENT
01170     // CHANGE angle definitions below to add curvature term
01171 
01172     if(real_imag && interleaved) {
01173       wfdata[2*n] = dat.real();
01174       wfdata[2*n+1] = dat.imag();
01175     } else if(real_imag && !interleaved) {
01176       wfdata[n] = dat.real();
01177       wfdata[n+this->diffractive_wavefront_header<T>::total_space()] = dat.imag();
01178     } else if(!real_imag && interleaved) {
01179       wfdata[2*n] = abs(dat);
01180       wfdata[2*n+1] = arg(dat);
01181     } else if(!real_imag && !interleaved) {
01182       wfdata[n] = abs(dat);
01183       wfdata[n+this->diffractive_wavefront_header<T>::total_space()] = arg(dat);
01184     }
01185   }
01186   
01187   template<class T>
01188     void diffractive_wavefront<T>::set_propagation_direction(const three_vector & prop_dir){
01189 
01190     if(prop_dir.length()<three_frame::precision){
01191       cerr << "diffractive_wavefront::update error - "
01192            << "propagation direction vector provided to this function is null\n";
01193       throw(string("diffractive_wavefront::update"));
01194     } 
01195 
01196     three_vector normalized_prop_dir = prop_dir * (1/prop_dir.length());
01197 
01198     if(cross_product(normalized_prop_dir, this->z()).length()<three_frame::precision)
01199       return;
01200 
01201     this->amp_phase_conversion();
01202 
01203     // modify wf phase to absorb tilt introduced by changing
01204     // propagation direction
01205     double x_halfpix=0, y_halfpix=0;
01206     int x_extrapix=1, y_extrapix=1;
01207     if(this->axes[1]%2==0){
01208       x_halfpix = .5;
01209       x_extrapix = 0;
01210     }
01211     if(this->axes[0]%2==0){
01212       y_halfpix = .5;
01213       y_extrapix = 0;
01214     }
01215 
01216     // Slopes are in radians of phase delay per pixel
01217     double xslope = 2*M_PI*this->get_pixel_scale()/this->get_wavelength()*
01218       dot_product(normalized_prop_dir, this->x());
01219     double yslope = 2*M_PI*this->get_pixel_scale()/this->get_wavelength()*
01220       dot_product(normalized_prop_dir, this->y());
01221     /*
01222     cout << "dot products " << dot_product(normalized_prop_dir, this->x())
01223          << "\t" << dot_product(normalized_prop_dir, this->y()) << endl;
01224     cout << "xslope " << xslope << " yslope " << yslope << endl;
01225     */
01226     if(interleaved) {
01227       for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++)
01228         for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++)
01229           if(wfdata[2*((i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2)]!=0)
01230             wfdata[2*((i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2)+1] += 
01231               (i+x_halfpix)*xslope + (j+y_halfpix)*yslope;
01232     } else {
01233       int nelem = this->axes[0]*this->axes[1];
01234       for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++)
01235         for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++)
01236           if(wfdata[(i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2]!=0)
01237             wfdata[(i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2+nelem+1] += 
01238               (i+x_halfpix)*xslope + (j+y_halfpix)*yslope;
01239     }
01240 
01241     // Rotate the wf three_frame so that its z axis lies along prop_dir
01242     three_vector axis_of_rotation = cross_product(this->z(), normalized_prop_dir);
01243     double rotation_angle = asin(axis_of_rotation.length());
01244     //Arroyo::three_rotation trot(*this, axis_of_rotation, -rotation_angle);
01245     Arroyo::three_rotation trot(*this, axis_of_rotation, rotation_angle);
01246     trot.transform(*this);
01247 
01248   }
01249 
01250   template<class T>
01251     void diffractive_wavefront<T>::set_wavefront_curvature(double curvature){
01252 
01253     this->amp_phase_conversion();
01254     this->interleaved_conversion();
01255     
01256     // modify wf phase to absorb curvature in header
01257 
01258     double x_halfpix=0, y_halfpix=0;
01259     int x_extrapix=1, y_extrapix=1;
01260     if(this->axes[1]%2==0){
01261       x_halfpix = .5;
01262       x_extrapix = 0;
01263     }
01264     if(this->axes[0]%2==0){
01265       y_halfpix = .5;
01266       y_extrapix = 0;
01267     }
01268 
01269     // NOTE: positive curvature indicates diverging beam. 
01270 
01271     double curvature_term = 
01272       (this->get_curvature() - curvature)*M_PI*this->get_pixel_scale()*this->get_pixel_scale()/this->wavelength;
01273     
01274     int index;
01275     double twopi = 2*M_PI;
01276 
01277     for(int i=-this->axes[1]/2; i<this->axes[1]/2+x_extrapix; i++){
01278       for(int j=-this->axes[0]/2; j<this->axes[0]/2+y_extrapix; j++){
01279         index = 2*((i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2);
01280         if(wfdata[index]!=0)
01281           wfdata[index+1] =
01282             fmod(wfdata[index+1] + 
01283                  curvature_term*((i+x_halfpix)*(i+x_halfpix)+(j+y_halfpix)*(j+y_halfpix)),
01284                  twopi);
01285       }
01286     }
01287   
01288     this->set_curvature(curvature);
01289   }
01290 
01291   template<class T>
01292     void diffractive_wavefront<T>::write_amps_to_ppm(double min, double max,
01293                                                      bool logscale,
01294                                                      bool colorbar,
01295                                                      colormap * cmap, 
01296                                                      const char * filename,
01297                                                      long min_dimen) const {
01298 
01299     this->extract_amps().write_to_ppm(min, max, logscale, colorbar, cmap, filename, min_dimen);
01300   }
01301 
01302   template<class T>
01303     void diffractive_wavefront<T>::write_phases_to_ppm(double min, double max, 
01304                                                        bool colorbar,
01305                                                        colormap * cmap, 
01306                                                        const char * filename,
01307                                                        long min_dimen) const {
01308 
01309     this->extract_phases().write_to_ppm(min, max, false, colorbar, cmap, filename, min_dimen);
01310   }
01311 
01312   template<class T>
01313     void diffractive_wavefront<T>::geometric_propagator(double distance) {
01314     this->three_point::operator+=(distance*this->z());
01315     if(this->curvature!=0){
01316       double initial_position = 1/this->curvature;
01317       this->pixel_scale *= (initial_position+distance)/initial_position;
01318       this->curvature = 1/(initial_position+distance);
01319     }
01320   } 
01321 
01322   template<class T>
01323     void diffractive_wavefront<T>::exact_propagator(double distance, 
01324                                                     double final_pixel_scale, 
01325                                                     vector<long> final_axes) {
01326 
01327     int nelem = this->diffractive_wavefront_header<T>::total_space();
01328     if(nelem==0){
01329       cerr << "diffractive_wavefront::exact_propagator error - "
01330            << "cannot propagate this diffractive_wavefront, as it has no data\n";
01331       throw(string("diffractive_wavefront::exact_propagator"));
01332     }
01333 
01334     if(final_pixel_scale==-1){
01335       final_pixel_scale = this->pixel_scale;
01336       final_axes = this->axes;
01337     }
01338 
01339     if(this->pixel_scale<0){
01340       cerr << "diffractive_wavefront::exact_propagator error - "
01341            << "requested pixel scale " << this->pixel_scale 
01342            << " less than zero\n";
01343       throw(string("diffractive_wavefront::exact_propagator"));
01344     }
01345 
01346     if(final_axes.size()!=2 || final_axes[0]<=0 || final_axes[1]<=0){
01347       cerr << "diffractive_wavefront::exact_propagator error - "
01348            << "requested axes invalid\n";
01349       for(int i=0; i<this->axes.size(); i++)
01350         cerr << "\taxis " << i << "\t" << final_axes[i] << endl;
01351       throw(string("diffractive_wavefront::exact_propagator"));
01352     }
01353    
01354     // this array holds the new pixel data
01355     // in non-interleaved format.  
01356     int new_nelem = final_axes[0]*final_axes[1];
01357     T * newdata;
01358     try{newdata = new T[2*new_nelem];}
01359     catch(...){
01360       cerr << "diffractive_wavefront::exact_propagator error - "
01361            << "could not allocate memory\n";
01362       throw(string("diffractive_wavefront::exact_propagator"));
01363     }
01364       
01365     double initial_power;
01366 
01367     if(wavefront::verbose_level) initial_power = this->total_power();
01368 
01369     // the half pixel definitions - so that
01370     // when you have even axes the pixel
01371     // centroids lie on half pixel values.
01372     double old_x_halfpix=0, old_y_halfpix=0;
01373     double new_x_halfpix=0, new_y_halfpix=0;
01374     int old_x_extrapix=1, old_y_extrapix=1;
01375     int new_x_extrapix=1, new_y_extrapix=1;
01376     if(this->axes[1]%2==0){
01377       old_x_halfpix = .5;
01378       old_x_extrapix = 0;
01379     }
01380     if(this->axes[0]%2==0){
01381       old_y_halfpix = .5;
01382       old_y_extrapix = 0;
01383     }
01384 
01385     if(final_axes[1]%2==0){
01386       new_x_halfpix = .5;
01387       new_x_extrapix = 0;
01388     }
01389     if(final_axes[0]%2==0){
01390       new_y_halfpix = .5;
01391       new_y_extrapix = 0;
01392     }
01393 
01394     this->real_imag_conversion();
01395     this->interleaved_conversion();
01396 
01397     // Here we're unnecessarily computing the same sqrt 4 times - once
01398     // for each quadrant.  We should really do the loop over just one
01399     // quadrant to cut down on compute time.  However, the original data
01400     // is not necessarily symmetric - just the sqrt.  The minor difficulty
01401     // is that if we do this, we need to determine whether axes are even
01402     // or odd, and if odd treat the center row and column separately
01403     double pixel_to_pixel_distance;
01404     double phase, cos_phase, sin_phase;
01405     double distance_squared = distance*distance;
01406     double real, imag;
01407     double wavenumber = 2*M_PI/this->wavelength;
01408     double fac, obliquity;
01409     double twopi = M_PI * 2;
01410     int curvature_sign = this->curvature>0 ? 1 : -1;
01411 
01412     for(int i=-final_axes[1]/2; i<final_axes[1]/2+new_x_extrapix; i++){
01413       for(int j=-final_axes[0]/2; j<final_axes[0]/2+new_y_extrapix; j++){
01414 
01415         real = imag = 0;
01416 
01417         for(int k=-this->axes[1]/2; k<this->axes[1]/2+old_x_extrapix; k++){
01418           for(int l=-this->axes[0]/2; l<this->axes[0]/2+old_y_extrapix; l++){
01419           
01420             if(wfdata[2*((k+this->axes[1]/2)*this->axes[0]+l+this->axes[0]/2)]==0 && 
01421                wfdata[2*((k+this->axes[1]/2)*this->axes[0]+l+this->axes[0]/2)+1]==0)
01422               continue;
01423 
01424             pixel_to_pixel_distance = 
01425               sqrt(distance_squared +
01426                    ((i+new_x_halfpix)*final_pixel_scale-(k+old_x_halfpix)*this->pixel_scale)*
01427                    ((i+new_x_halfpix)*final_pixel_scale-(k+old_x_halfpix)*this->pixel_scale) +
01428                    ((j+new_y_halfpix)*final_pixel_scale-(l+old_y_halfpix)*this->pixel_scale)*
01429                    ((j+new_y_halfpix)*final_pixel_scale-(l+old_y_halfpix)*this->pixel_scale));
01430           
01431             obliquity = distance/pixel_to_pixel_distance;
01432             phase = pixel_to_pixel_distance*wavenumber - M_PI_2;
01433 
01434             // Term to account for the extra propagation distance if
01435             // wavefront has finite curvature.  The exact quantity is
01436             // sqrt(lateral_displacement^{2}+1/(curvature^{2})) -
01437             // 1/curvature.
01438             if(this->curvature)
01439               phase += curvature_sign*
01440                 (sqrt(this->pixel_scale*this->pixel_scale*((k+old_x_halfpix)*(k+old_x_halfpix)+
01441                                                            (l+old_y_halfpix)*(l+old_y_halfpix)) + 
01442                       1/(this->curvature*this->curvature)) - 1/this->curvature)/this->wavelength;
01443             
01444             cos_phase = cos(phase);
01445             sin_phase = sin(phase);
01446             fac = obliquity*this->pixel_scale*this->pixel_scale/pixel_to_pixel_distance/this->wavelength;
01447           
01448             real += fac *
01449               (wfdata[2*((k+this->axes[1]/2)*this->axes[0]+l+this->axes[0]/2)]*cos_phase - 
01450                wfdata[2*((k+this->axes[1]/2)*this->axes[0]+l+this->axes[0]/2)+1]*sin_phase);
01451             imag += fac *
01452               (wfdata[2*((k+this->axes[1]/2)*this->axes[0]+l+this->axes[0]/2)]*sin_phase +
01453                wfdata[2*((k+this->axes[1]/2)*this->axes[0]+l+this->axes[0]/2)+1]*cos_phase);
01454 
01455             /*
01456               if(i==0&&j==0)
01457               cout << setw(5) << k << setw(5) << l 
01458               << setw(12) << obliquity 
01459               << setw(12) << fmod(phase,twopi)
01460               << setw(12) << fac 
01461               << setw(12) << wfdata[2*((k+axes[1]/2)*axes[0]+l+axes[0]/2)]
01462               << setw(12) << wfdata[2*((k+axes[1]/2)*axes[0]+l+axes[0]/2)+1]
01463               << setw(12) << real 
01464               << setw(12) << imag << endl;
01465             */
01466           }
01467         }       
01468 
01469         newdata[2*((i+final_axes[1]/2)*final_axes[0]+j+final_axes[0]/2)] = real;
01470         newdata[2*((i+final_axes[1]/2)*final_axes[0]+j+final_axes[0]/2)+1] = imag;
01471 
01472       } 
01473     }
01474 
01475     delete [] this->wfdata;
01476     this->wfdata = newdata;
01477     this->axes = final_axes;
01478 
01479     if(wavefront::verbose_level) {
01480       double final_power = this->total_power();
01481       cout << "initial power " << initial_power << " final power " << final_power
01482            << " ratio "  << final_power / initial_power << endl;
01483     }
01484 
01485     this->pixel_scale = final_pixel_scale;
01486     this->curvature = 0;
01487 
01488     three_translation tt(distance*this->three_frame::z());
01489     tt.transform(*this);
01490     update_timestamp(distance);
01491   }
01492 
01493   template<class T>
01494     void diffractive_wavefront<T>::forward_fft() {
01495     vector<long> flipped_axes(2, this->axes[0]);
01496     flipped_axes[0] = this->axes[1];
01497     //this->mk_fftw_plan(flipped_axes, false, true, FFTW_FORWARD);
01498     this->real_imag_conversion();
01499     this->interleaved_conversion();  
01500     this->fft_manager<T>::forward_fft(flipped_axes, false, true, wfdata);
01501   }
01502 
01503   template<class T>
01504     void diffractive_wavefront<T>::backward_fft(){
01505     vector<long> flipped_axes(2, this->axes[0]);
01506     flipped_axes[0] = this->axes[1];
01507     //this->mk_fftw_plan(flipped_axes, false, true, FFTW_BACKWARD);
01508     this->real_imag_conversion();
01509     this->interleaved_conversion();  
01510     this->fft_manager<T>::backward_fft(flipped_axes, false, true, wfdata);
01511   }
01512 
01513   namespace {
01514 
01515     // A convenience function to apply the near field transfer function
01516     // to the data
01517     //
01518     // This function requires that the input data be interleaved
01519     template<class T>
01520       void apply_transfer_function(double axial_phase, vector<long> axes, 
01521                                    vector<double> phase_coefficient, bool fresnel, T * wfdata){
01522 
01523       double twopi = 2*M_PI;
01524       double x_halfpix=0, y_halfpix=0;
01525       int x_extrapix=1, y_extrapix=1;
01526       if(axes[1]%2==0){
01527         x_halfpix = .5;
01528         x_extrapix = 0;
01529       }
01530       if(axes[0]%2==0){
01531         y_halfpix = .5;
01532         y_extrapix = 0;
01533       }
01534 
01535       int index;
01536       double tmp_val, xfer_fn_phase;
01537       Arroyo::complex_cyclic_permutation(axes, axes[0]/2, axes[1]/2, wfdata);
01538       for(int i=-axes[1]/2; i<axes[1]/2+x_extrapix; i++){
01539         for(int j=-axes[0]/2; j<axes[0]/2+y_extrapix; j++){
01540           index = (i+axes[1]/2)*axes[0]+j+axes[0]/2;
01541           tmp_val = phase_coefficient[1]*(i+x_halfpix)*(i+x_halfpix) + 
01542             phase_coefficient[0]*(j+y_halfpix)*(j+y_halfpix);
01543           
01544           if(tmp_val>1){
01545             wfdata[2*i*axes[0]] = 0;
01546             wfdata[2*(axes[1]-i)*axes[0]] = 0;       
01547           } else {
01548             if(fresnel) xfer_fn_phase = fmod((axial_phase*(1 - .5*tmp_val)),twopi);
01549             else xfer_fn_phase = fmod((axial_phase*sqrt(1 - tmp_val)),twopi);
01550             wfdata[2*index+1] += xfer_fn_phase;
01551           }
01552         }
01553       }
01554       Arroyo::complex_cyclic_permutation(axes, -axes[0]/2, -axes[1]/2, wfdata);
01555     }
01556 
01557     // A convenience function to apply the near field transfer function
01558     // to the data
01559     //
01560     // This function requires that the input data be interleaved
01561     template<class T>
01562       void optimized_apply_transfer_function(double axial_phase, vector<long> axes, 
01563                                              vector<double> phase_coefficient, bool fresnel, T * wfdata){
01564 
01565       // In the following application of the transfer function, we check
01566       // to see whether the sqrt is going to have a negative argument.
01567       // This condition indicates evanescent waves, so we set the transfer
01568       // function to zero.  See Goodman "Introduction to Fourier Optics"
01569       // eq. 3-47 for more explanation
01570       
01571       // First, do the transfer function for the dc elements
01572       // if one or both axes are even, then at the same time we do nyquist
01573       bool odd_zero = axes[0]%2;
01574       int lim_one = axes[1]/2+axes[1]%2;
01575       double xfer_fn_phase;
01576       double tmp_val;
01577       double twopi = 2*M_PI;
01578 
01579       for(int i=1; i<lim_one; i++){
01580 
01581         tmp_val = phase_coefficient[1]*i*i;
01582         if(tmp_val>1){
01583           wfdata[2*i*axes[0]] = 0;
01584           wfdata[2*(axes[1]-i)*axes[0]] = 0;       
01585         } else {
01586           if(fresnel) xfer_fn_phase = fmod((axial_phase*(1 - .5*tmp_val)), twopi);
01587           else xfer_fn_phase = fmod((axial_phase*sqrt(1 - tmp_val)), twopi);
01588           wfdata[2*i*axes[0]+1] += xfer_fn_phase;
01589           wfdata[2*(axes[1]-i)*axes[0]+1] += xfer_fn_phase;
01590         }
01591 
01592         if(!odd_zero){
01593           tmp_val = phase_coefficient[1]*i*i + phase_coefficient[0]*axes[0]/2*axes[0]/2;
01594           if(tmp_val>1){
01595             wfdata[2*(i*axes[0]+axes[0]/2)] = 0; 
01596             wfdata[2*((axes[1]-i)*axes[0]+axes[0]/2)] = 0;
01597           } else {
01598             if(fresnel) xfer_fn_phase = fmod((axial_phase*(1 - .5*tmp_val)), twopi);
01599             else xfer_fn_phase = fmod((axial_phase*sqrt(1 - tmp_val)),twopi);
01600             wfdata[2*(i*axes[0]+axes[0]/2)+1] += xfer_fn_phase; 
01601             wfdata[2*((axes[1]-i)*axes[0]+axes[0]/2)+1] += xfer_fn_phase; 
01602           }
01603         }
01604       }    
01605       
01606       bool odd_one = axes[1]%2;
01607       int lim_zero = axes[0]/2+axes[0]%2;
01608       for(int j=1; j<lim_zero; j++){
01609         
01610         tmp_val = phase_coefficient[0]*j*j;
01611         if(tmp_val>1){
01612           wfdata[2*j] = 0;
01613           wfdata[2*(axes[0]-j)] = 0;
01614         } else {
01615           if(fresnel) xfer_fn_phase = fmod((axial_phase*(1 - .5*tmp_val)),twopi);
01616           else xfer_fn_phase = fmod((axial_phase*sqrt(1 - tmp_val)),twopi);
01617           wfdata[2*j+1] += xfer_fn_phase;
01618           wfdata[2*(axes[0]-j)+1] += xfer_fn_phase;
01619         }
01620         
01621         if(!odd_one){
01622           tmp_val = phase_coefficient[0]*j*j + phase_coefficient[1]*axes[1]/2*axes[1]/2;
01623           if(tmp_val>1){
01624             wfdata[2*(axes[1]/2*axes[0]+j)] = 0;
01625             wfdata[2*(axes[1]/2*axes[0]+axes[0]-j)] = 0;
01626           } else {
01627             if(fresnel) xfer_fn_phase = fmod((axial_phase*(1 - .5*tmp_val)),twopi);
01628             else xfer_fn_phase = fmod((axial_phase*sqrt(1 - tmp_val)),twopi);
01629             wfdata[2*(axes[1]/2*axes[0]+j)+1] += xfer_fn_phase;
01630             wfdata[2*(axes[1]/2*axes[0]+axes[0]-j)+1] += xfer_fn_phase;
01631           }
01632         }
01633       }
01634       // The last 4 points we missed by indexing 
01635       // loops from one rather than from zero
01636       // This indexing was required because DC and nyquist
01637       // must be treated differently by the transfer function,
01638       // whereas all other points have symmetric properties
01639       // when i=>-i or j=>-j
01640       wfdata[1] += axial_phase;
01641       if(!odd_zero){
01642         tmp_val = phase_coefficient[0]*axes[0]/2*axes[0]/2;
01643         if(tmp_val>1) wfdata[axes[0]] = 0;
01644         else {
01645           if(fresnel) wfdata[axes[0]+1] += fmod((axial_phase*(1 - .5*tmp_val)),twopi);
01646           else wfdata[axes[0]+1] += fmod((axial_phase*sqrt(1 - tmp_val)),twopi);
01647         }
01648       }
01649       if(!odd_one){
01650         tmp_val = phase_coefficient[1]*axes[1]/2*axes[1]/2;
01651         if(tmp_val>1) wfdata[2*(axes[1]/2*axes[0])] = 0;
01652         else {
01653           if(fresnel) wfdata[2*(axes[1]/2*axes[0])+1] += fmod((axial_phase*(1 - .5*tmp_val)),twopi);
01654           else wfdata[2*(axes[1]/2*axes[0])+1] += fmod((axial_phase*sqrt(1 - tmp_val)),twopi);
01655         }
01656       }
01657       if(!odd_zero && !odd_one){
01658         tmp_val = phase_coefficient[0]*axes[0]/2*axes[0]/2 + phase_coefficient[1]*axes[1]/2*axes[1]/2;
01659         if(tmp_val>1) wfdata[2*(axes[1]/2*axes[0]+axes[0]/2)] = 0;
01660         else {
01661           if(fresnel) wfdata[2*(axes[1]/2*axes[0]+axes[0]/2)+1] += fmod((axial_phase*(1 - .5*tmp_val)),twopi);
01662           else wfdata[2*(axes[1]/2*axes[0]+axes[0]/2)+1] += fmod((axial_phase*sqrt(1 - tmp_val)),twopi);
01663         }
01664       }
01665       
01666       // Now do the rest of the data - easy since
01667       // the transfer function in the 4 quadrants 
01668       // is symmetric
01669       for(int i=1; i<lim_one; i++){
01670         for(int j=1; j<lim_zero; j++){
01671           tmp_val = phase_coefficient[1]*i*i + phase_coefficient[0]*j*j;
01672           if(tmp_val>1){
01673             wfdata[2*(i*axes[0]+j)] = 0;
01674             wfdata[2*((axes[1]-i)*axes[0]+j)] = 0;
01675             wfdata[2*(i*axes[0]+axes[0]-j)] = 0;
01676             wfdata[2*((axes[1]-i)*axes[0]+axes[0]-j)] = 0;
01677           } else {
01678             if(fresnel) xfer_fn_phase = fmod((axial_phase*(1 - .5*tmp_val)),twopi);
01679             else xfer_fn_phase = fmod((axial_phase*sqrt(1 - tmp_val)),twopi);
01680             wfdata[2*(i*axes[0]+j)+1] += xfer_fn_phase;
01681             wfdata[2*((axes[1]-i)*axes[0]+j)+1] += xfer_fn_phase;
01682             wfdata[2*(i*axes[0]+axes[0]-j)+1] += xfer_fn_phase;
01683             wfdata[2*((axes[1]-i)*axes[0]+axes[0]-j)+1] += xfer_fn_phase;
01684           }
01685         }
01686       }
01687     }
01688   }
01689 
01690   template<class T>
01691     void diffractive_wavefront<T>::near_field_propagator(double distance, bool fresnel) {
01692 
01693     // NOTES:
01694     //   For verging beams, remember that you have to operate
01695     //   on a diffractive_wavefront from which the curvature has been removed.
01696     //   In this case, you do the regular thing but use a different
01697     //   distance.  Then you fix things up at the end.
01698 
01699     if(wavefront::verbose_level>2){
01700       string fname = "angular_pre_backwards_fft_diffractive_wavefront.fits";
01701       if(fresnel)
01702         fname = "fresnel_pre_backwards_fft_diffractive_wavefront.fits";
01703       cout << "diffractive_wavefront::near_field_propagator - writing initial diffractive_wavefront to file " 
01704            << fname << endl;
01705       this->write(fname.c_str());
01706     }
01707 
01708     // Perform inverse fourier transform
01709     if(diffractive_wavefront::wavefront::verbose_level)
01710       cout << "diffractive_wavefront::near_field_propagator - performing backwards fft\n";
01711 
01712     this->forward_fft();
01713 
01714     this->amp_phase_conversion();
01715     this->interleaved_conversion();
01716 
01717     // This factor will multiply the indices to produce the correct
01718     // value in the exponential phase term.  It's effect includes
01719     // conversion from pixels to frequency interval, plus the prefactor
01720     // of M_PI*dist*wavelength.  The conversion to frequency interval
01721     // depends on the dimensionality of the axis, so this factor may
01722     // differ between the two axes See GLAD manual page 4.15
01723     vector<double> phase_coefficient(2);
01724     phase_coefficient[0] = this->wavelength*this->wavelength/(this->pixel_scale*this->pixel_scale*this->axes[0]*this->axes[0]); 
01725     phase_coefficient[1] = this->wavelength*this->wavelength/(this->pixel_scale*this->pixel_scale*this->axes[1]*this->axes[1]);
01726 
01727     // this is the phase of light travelling directly down the optical axis
01728     double axial_phase = 2*M_PI*distance/this->wavelength;
01729     double effective_distance = distance/(this->curvature*distance+1);
01730 
01731     if(this->curvature)
01732       axial_phase = 2*M_PI*effective_distance/this->wavelength;
01733 
01734     int nelem = this->axes[0]*this->axes[1];
01735 
01736     //apply_transfer_function(axial_phase, axes, phase_coefficients, fresnel, wfdata);
01737     optimized_apply_transfer_function(axial_phase, this->axes, phase_coefficient, fresnel, wfdata);
01738 
01739     // Perform fourier transform
01740     this->backward_fft();
01741 
01742     if(wavefront::verbose_level>2){
01743       string fname = "angular_forwards_fft_xfer_diffractive_wavefront.fits";
01744       if(fresnel) fname = "fresnel_post_backwards_fft_diffractive_wavefront.fits";
01745       cout << "diffractive_wavefront::near_field_propagator - "
01746            << "writing back-transformed diffractive_wavefront with transfer function applied to file " 
01747            << fname << endl;
01748       this->write(fname.c_str());
01749     }
01750 
01751     // FFTW leaves a factor of N*M 
01752     // after forward and backward fft
01753     double inv = 1/(1+distance*this->curvature)/(double)(this->axes[0]*this->axes[1]);
01754     for(int i=0; i<2*nelem; i++)
01755       wfdata[i] *= inv;
01756 
01757     if(this->curvature){
01758       this->pixel_scale *= (1+distance*this->curvature);
01759       this->curvature = 1/(distance+1/this->curvature);
01760     }
01761 
01762     this->three_point::operator+=(distance*this->three_frame::z());
01763     update_timestamp(distance);
01764   }
01765 
01766   template<class T>
01767     void diffractive_wavefront<T>::near_field_angular_propagator(double distance) {
01768     this->near_field_propagator(distance, false);
01769   }
01770 
01771   template<class T>
01772     void diffractive_wavefront<T>::near_field_fresnel_propagator(double distance) {
01773     this->near_field_propagator(distance, true);
01774   }
01775 
01776 
01777   // Be very careful about changing this function - four different
01778   // propagators rely on it.
01779   // NOTE:  when you add in the curvature data member
01780   //        to diffractive_wavefront, you will have to include 
01781   //        operations using this term in this function
01782   template<class T>
01783     void diffractive_wavefront<T>::far_field_propagator(double distance, 
01784                                                         bool fresnel, 
01785                                                         double final_pixel_scale, 
01786                                                         vector<long> final_axes) {
01787 
01788 
01789     bool goertzel_reinsch = false;
01790     if(final_axes.size()==2 && final_pixel_scale>0)
01791       goertzel_reinsch = true;
01792     else if((final_axes.size()!=0 && final_axes.size()!=2) ||
01793             final_pixel_scale!=-1){
01794       cout << "diffractive_wavefront::far_field_propagator error - " 
01795            << "this function was invoked by implicitly requesting " << endl
01796            << "propagation using the Goertzel-Reinsch algorithm - " << endl
01797            << "but this invocation was corrupt."  << endl
01798            << "Specifically, the requested final pixel scale was " 
01799            << final_pixel_scale << " and the requested axes were\n";
01800       for(int i=0; i<final_axes.size(); i++)
01801         cout << final_axes[i] << endl;
01802       throw(string("diffractive_wavefront::far_field_propagator"));
01803     }
01804 
01805     if(wavefront::verbose_level){
01806       if(fresnel && goertzel_reinsch)
01807         cout << "diffractive_wavefront::far_field_propagator - applying fresnel goertzel reinsch propagator\n";
01808       else if(!fresnel && goertzel_reinsch)
01809         cout << "diffractive_wavefront::far_field_propagator - applying fraunhoffer goertzel reinsch propagator\n";
01810       else if(fresnel && !goertzel_reinsch)
01811         cout << "diffractive_wavefront::far_field_propagator - applying fresnel propagator\n";
01812       else
01813         cout << "diffractive_wavefront::far_field_propagator - applying fraunhoffer propagator\n";
01814     }
01815 
01816     if(!goertzel_reinsch && (this->axes[0]!=this->axes[1])){
01817       cerr << "diffractive_wavefront::far_field_propagator error - "
01818            << "cannot perform a far field propagation via fft " << endl
01819            << "on an input array with axes of different size, "
01820            << "because the software can only handle square pixels\n";
01821       cerr << "If you need to do this, try the Goertzel-Reinsch propagators\n";
01822       throw(string("diffractive_wavefront::far_field_propagator"));
01823     }
01824 
01825     this->interleaved_conversion();
01826     this->amp_phase_conversion();
01827 
01828     // Correct for halfpixel values At the same time, adjust the phase
01829     // slope to generate half a pixel shift in the image plane, so that
01830     // DC is not off-center For fresnel propagation, we also apply the
01831     // quadratic phase term.  Finally, we renormalize the amplitudes
01832     //
01833     // There's a subtlety here with half pixels DC is at 0,0.  We need
01834     // to put the center of the diffractive_wavefront there.  If the
01835     // diffractive_wavefront has an even number of pixels, we end up
01836     // with a phase slope in the image plane corresponding to half a
01837     // pixel shift in the pupil plane.  Likewise, after the
01838     // transformation we end up with a DC term at 0,0, which corresponds
01839     // to the center of the array.  Again if there are an even number of
01840     // pixels across the array we end up with a half pixel shift after
01841     // reordering the quadrants.  So we use the shift theorem to fix
01842     // things up, taking out a phase slope in the pupil plane to account
01843     // for the image plane half pixel shift, and subtracting a phase
01844     // slope in the image plane to account for the half pixel shift in
01845     // the pupil plane.  These effects cancel out in the near field
01846     // propagator case because we do both a forward and backward fft.
01847 
01848     vector<long> initial_axes(this->axes);
01849 
01850     double initial_x_halfpix=0, initial_y_halfpix=0;
01851     int initial_x_extrapix=1, initial_y_extrapix=1;
01852     if(initial_axes[1]%2==0){
01853       initial_x_halfpix = .5;
01854       initial_x_extrapix = 0;
01855     }
01856     if(initial_axes[0]%2==0){
01857       initial_y_halfpix = .5;
01858       initial_y_extrapix = 0;
01859     }
01860 
01861     if(final_axes.size()==0) final_axes = initial_axes;
01862 
01863     double final_x_halfpix=0, final_y_halfpix=0;
01864     int final_x_extrapix=1, final_y_extrapix=1;
01865     if(final_axes[1]%2==0){
01866       final_x_halfpix = .5;
01867       final_x_extrapix = 0;
01868     }
01869     if(final_axes[0]%2==0){
01870       final_y_halfpix = .5;
01871       final_y_extrapix = 0;
01872     }
01873 
01874     // definitions to account for halfpixel shifts for even final array dimensions
01875     double initial_pixel_scale = this->get_pixel_scale();
01876     double nyquist_pixel_scale = this->wavelength * distance / (double) initial_axes[0] / initial_pixel_scale;
01877     if(final_pixel_scale==-1) final_pixel_scale = nyquist_pixel_scale;
01878     double xslope = final_axes[1]%2==1 ? 0 : M_PI*final_pixel_scale/nyquist_pixel_scale/(double)initial_axes[1];
01879     double yslope = final_axes[0]%2==1 ? 0 : M_PI*final_pixel_scale/nyquist_pixel_scale/(double)initial_axes[0];
01880 
01881     // Term to account for the extra propagation distance if
01882     // wavefront has finite curvature.  The exact quantity is
01883     // sqrt(lateral_displacement^{2}+1/(curvature^{2})) -
01884     // 1/curvature, but here we approximate this by
01885     // .5*lateral_displacement^{2}*curvature^{2}
01886     int index;
01887     double twopi = 2*M_PI;
01888     double initial_curvature_term = M_PI*initial_pixel_scale*initial_pixel_scale*this->curvature/this->wavelength;
01889     double quadratic_coefficient = 0;
01890     if(fresnel)
01891       quadratic_coefficient = M_PI*initial_pixel_scale*initial_pixel_scale/this->wavelength/distance;
01892 
01893     for(int i=-initial_axes[1]/2; i<initial_axes[1]/2+initial_x_extrapix; i++){
01894       for(int j=-initial_axes[0]/2; j<initial_axes[0]/2+initial_y_extrapix; j++){
01895         index = (i+initial_axes[1]/2)*initial_axes[0]+j+initial_axes[0]/2;
01896 
01897         wfdata[2*index+1] += 
01898           fmod(((quadratic_coefficient + initial_curvature_term)*
01899                 ((i+initial_x_halfpix)*(i+initial_x_halfpix)+(j+initial_y_halfpix)*(j+initial_y_halfpix))
01900                 - xslope*(i+initial_x_halfpix) - yslope*(j+initial_y_halfpix)), twopi);
01901       }
01902     }
01903 
01904     if(wavefront::verbose_level>2){
01905       string fname = "far_field_fraunhoffer_xfer_diffractive_wavefront.fits";
01906       if(fresnel && goertzel_reinsch) fname = "far_field_fresnel_goertzel_reinsch_xfer_diffractive_wavefront.fits";
01907       else if(!fresnel && goertzel_reinsch) fname = "far_field_fraunhoffer_goertzel_reinsch_xfer_diffractive_wavefront.fits";
01908       else if(fresnel && !goertzel_reinsch) fname = "far_field_fresnel_xfer_diffractive_wavefront.fits";
01909       cout << "diffractive_wavefront::far_field_propagator - "
01910            << "writing diffractive_wavefront with transfer function applied to file " 
01911            << fname << endl;
01912       this->write(fname.c_str());
01913     }
01914 
01915     // for the normalization factor, we have one factor of
01916     // 1/wavelength/distance for the prefactor, two more for changing
01917     // variables in the fft.  Then we have two factors of the pixel
01918     // scale for each of the two dimensions
01919     double normalization_factor = 
01920       fabs((double)(initial_pixel_scale*initial_pixel_scale/this->wavelength/distance));
01921 
01922     if(goertzel_reinsch){
01923       long dimen = 2*final_axes[0]*final_axes[1];
01924       T * newdata;
01925       try{newdata = new T[dimen];}
01926       catch(...){
01927         cerr << "diffractive_wavefront::far_field_propagator error - "
01928              << "unable to allocate memory\n";
01929         throw(string("diffractive_wavefront::far_field_propagator"));
01930       }
01931 
01932       this->real_imag_conversion();
01933       // negative sampling factor for forward fft
01934       double sampling_factor = -initial_pixel_scale*final_pixel_scale / this->wavelength / distance;
01935       goertzel_reinsch_transform(initial_axes, final_axes, sampling_factor, wfdata, newdata);
01936       delete [] wfdata;
01937       wfdata = newdata;
01938       this->axes = final_axes;
01939     } else {
01940       this->cyclic_permutation(initial_axes[0]/2, initial_axes[1]/2);
01941       // Perform inverse fourier transform
01942       if(wavefront::verbose_level)
01943         cout << "diffractive_wavefront::far_field_propagator - performing backwards fft\n";
01944       this->forward_fft();
01945       this->cyclic_permutation(-initial_axes[0]/2, -initial_axes[1]/2);
01946     }
01947 
01948     if(wavefront::verbose_level>2){
01949       string fname = "far_field_fraunhoffer_xformed_diffractive_wavefront.fits";
01950       if(fresnel && goertzel_reinsch) fname = "far_field_fresnel_goertzel_reinsch_xformed_diffractive_wavefront.fits";
01951       else if(!fresnel && goertzel_reinsch) fname = "far_field_fraunhoffer_goertzel_reinsch_xformed_diffractive_wavefront.fits";
01952       else if(fresnel && !goertzel_reinsch) fname = "far_field_fresnel_xformed_diffractive_wavefront.fits";
01953       cout << "diffractive_wavefront::far_field_propagator - "
01954            << "writing transformed diffractive_wavefront to file " 
01955            << fname << endl;
01956       this->write(fname.c_str());
01957     }
01958 
01959 
01960     // redefinitions to account for halfpixel shifts for even initial array dimensions
01961     nyquist_pixel_scale = this->wavelength * distance / (double) final_axes[0] / final_pixel_scale;
01962     xslope = initial_axes[1]%2==1 ? 0 : M_PI*initial_pixel_scale/nyquist_pixel_scale/(double)final_axes[1];
01963     yslope = initial_axes[0]%2==1 ? 0 : M_PI*initial_pixel_scale/nyquist_pixel_scale/(double)final_axes[0];
01964 
01965     // Apply the quadratic phase term to the diffractive_wavefront
01966     // this time, the normalization factor is used to 
01967     // normalize away the dimensional factor that arises
01968     // in a forwards to backwards fft
01969     this->amp_phase_conversion();
01970     quadratic_coefficient = final_pixel_scale*final_pixel_scale*M_PI/this->wavelength/distance;
01971     double constant_phase = 2*M_PI*fmod(distance/this->wavelength,1.0) - M_PI_2;
01972     for(int i=-final_axes[1]/2; i<final_axes[1]/2+final_x_extrapix; i++){
01973       for(int j=-final_axes[0]/2; j<final_axes[0]/2+final_y_extrapix; j++){
01974         index = (i+final_axes[1]/2)*final_axes[0]+j+final_axes[0]/2;
01975         wfdata[2*index] *= normalization_factor;
01976         wfdata[2*index+1] += constant_phase - xslope*(i + final_x_halfpix) - yslope*(j + final_y_halfpix);
01977         if(fresnel)
01978           wfdata[2*index+1] = 
01979             fmod(wfdata[2*index+1] + M_PI + quadratic_coefficient*
01980                  ((i+final_x_halfpix)*(i+final_x_halfpix)+(j+final_y_halfpix)*(j+final_y_halfpix)), twopi) - M_PI_2;
01981       }
01982     }
01983     
01984     this->pixel_scale = final_pixel_scale;
01985     this->three_point::operator+=(distance*this->three_frame::z());
01986     this->curvature = 0;
01987     update_timestamp(distance);
01988   }
01989 
01990   template<class T>
01991     void diffractive_wavefront<T>::far_field_fresnel_propagator(double distance) {
01992     this->far_field_propagator(distance, true);
01993   }
01994 
01995   template<class T>
01996     void diffractive_wavefront<T>::far_field_fraunhoffer_propagator(double distance) {
01997     this->far_field_propagator(distance, false);
01998   }
01999 
02000   template<class T>
02001     void diffractive_wavefront<T>::far_field_fresnel_goertzel_reinsch_propagator(double distance, 
02002                                                                                  double final_pixel_scale, 
02003                                                                                  vector<long> final_axes) {
02004     this->far_field_propagator(distance, true, final_pixel_scale, final_axes);
02005   }
02006 
02007   template<class T>
02008     void diffractive_wavefront<T>::far_field_fraunhoffer_goertzel_reinsch_propagator(double distance, 
02009                                                                                      double final_pixel_scale, 
02010                                                                                      vector<long> final_axes) {
02011     this->far_field_propagator(distance, false, final_pixel_scale, final_axes);
02012   }
02013 
02014   template<class T>
02015     void diffractive_wavefront<T>::finite_difference_method_propagator(double distance) {
02016 
02017     // fast algorithm for short distance propagation
02018     cerr << "diffractive_wavefront::finite_difference_method_propagator error - "
02019          << "this function has not yet been coded\n";
02020     throw(string("diffractive_wavefront::finite_difference_method_propagator"));
02021 
02022   }
02023 
02024   template<class T>
02025     void diffractive_wavefront<T>::rotate(double angle) {
02026 
02027     //   To rotate a 2d data set through an angle a,
02028     //   you want to multiply each (x,y) pixel value
02029     //   by the matrix
02030     //  
02031     //   [  cos(a)   -sin(a)  ]
02032     //   [  sin(a)    cos(a)  ]
02033     //
02034     //   This is equivalent to multiplying by the 3 matrices
02035     // 
02036     //   [   1   -tan(a/2)  ] [   1      0][   1     -tan(a/2)  ]
02037     //   [   0      1       ] [ sin(a)   1][   0         1      ]
02038     //
02039     //  This multiplication may be performed in separate passes.
02040     //  It performs the rotation in place, and requires no
02041     //  reordering of the array.  However, it does rotate straight
02042     //  lines into bumpy, pixel resolved diagonal lines
02043     cerr << "diffractive_wavefront::rotate not yet coded\n";
02044     throw(string("diffractive_wavefront::rotate"));
02045 
02046   }
02047 
02048   template<class T>
02049     template<class U>
02050     void diffractive_wavefront<T>::pad_array(int npad, std::complex<U> value) {
02051 
02052     // NOTES:
02053     // This function still works if the diffractive_wavefront starts with no elements
02054 
02055     if(npad==0) return;
02056     if(npad<0){
02057       cerr << "diffractive_wavefront::pad_array error - cannot pad by " << npad << " pixels\n";
02058       throw(string("diffractive_wavefront::pad_array"));
02059     }
02060 
02061     vector<long> new_axes = this->axes;
02062     int old_nelem = diffractive_wavefront_header<T>::total_space();
02063     int nelem=1;
02064     for(int i=0; i<new_axes.size(); i++){
02065       new_axes[i] += 2*npad;
02066       nelem *= new_axes[i];
02067     }
02068 
02069     if(wavefront::verbose_level)
02070       cout << "diffractive_wavefront::pad_array - padding by " << npad 
02071            << " from " << this->axes[0] << "x" << this->axes[1]
02072            << " to " << new_axes[0] << "x" << new_axes[1] << endl;
02073 
02074     this->interleaved_conversion();
02075 
02076     T * olddata = wfdata;
02077     try{wfdata = new T[2*nelem];}
02078     catch(...){
02079       cerr << "diffractive_wavefront::pad_array error - "
02080            << "unable to allocate memory\n";
02081       throw(string("diffractive_wavefront::pad_array"));
02082     }
02083 
02084     if(this->real_imag){
02085       U real = value.real();
02086       U imag = value.imag();
02087       for(int i=0; i<nelem; i++){
02088         wfdata[2*i] = real;
02089         wfdata[2*i+1] = imag;
02090       }
02091     } else {
02092       U amp = abs(value);
02093       U phase = arg(value);
02094       for(int i=0; i<nelem; i++){
02095         wfdata[2*i] = amp;
02096         wfdata[2*i+1] = phase;
02097       }
02098     }      
02099 
02100     // copy the old data into the new array
02101     for(int i=0; i<this->axes[1]; i++)
02102       for(int j=0; j<this->axes[0]; j++){
02103         wfdata[2*((i+npad)*new_axes[0]+npad+j)] = 
02104           olddata[2*(i*this->axes[0]+j)];
02105         wfdata[2*((i+npad)*new_axes[0]+npad+j)+1] = 
02106           olddata[2*(i*this->axes[0]+j)+1];
02107       }
02108 
02109     delete [] olddata;
02110     this->axes = new_axes;
02111   }
02112 
02113   template<class T>
02114     void diffractive_wavefront<T>::clip_array(int nclip) {
02115 
02116     if(nclip==0) return;
02117     if(nclip<0){
02118       cerr << "diffractive_wavefront::clip_array error - cannot clip by " << nclip << " pixels\n";
02119       throw(string("diffractive_wavefront::clip_array"));
02120     }
02121 
02122     vector<long> new_axes = this->axes;
02123     int nelem = 1;
02124     for(int i=0; i<new_axes.size(); i++){
02125       new_axes[i] -= 2*nclip;
02126       if(new_axes[i]<=0){
02127         cerr << "diffractive_wavefront::clip_array error - clipping original array by "
02128              << nclip << " pixels leaves non-positive array size\n";
02129         throw(string("diffractive_wavefront::clip_array"));
02130       }
02131       nelem *= new_axes[i];
02132     }
02133     
02134     if(wavefront::verbose_level)
02135       cout << "diffractive_wavefront::clip_array - clipping by " << nclip
02136            << " from " << this->axes[0] << "x" << this->axes[1]
02137            << " to " << new_axes[0] << "x" << new_axes[1] << endl;
02138   
02139     T * newdata;
02140     try{newdata = new T[2*nelem];}
02141     catch(...){
02142       cerr << "diffractive_wavefront::pad_array error - "
02143            << "unable to allocate memory\n";
02144       throw(string("diffractive_wavefront::clip_array"));
02145     }
02146 
02147     this->interleaved_conversion();
02148 
02149     // copy the old data into the new array
02150     for(int i=0; i<new_axes[1]; i++)
02151       for(int j=0; j<new_axes[0]; j++){
02152         newdata[2*(i*new_axes[0]+j)] = 
02153           wfdata[2*((i+nclip)*this->axes[0]+nclip+j)];
02154         newdata[2*(i*new_axes[0]+j)+1] = 
02155           wfdata[2*((i+nclip)*this->axes[0]+nclip+j)+1];
02156       }
02157 
02158     // make the switcheroo
02159     delete [] wfdata;
02160     wfdata = newdata;
02161 
02162     this->axes = new_axes;
02163   } 
02164 
02165   template<class T>
02166     double diffractive_wavefront<T>::total_power() const {
02167 
02168     double total_power = 0;
02169     int nelem = diffractive_wavefront_header<T>::total_space();
02170     if(real_imag){
02171       for(int i=0; i<2*nelem; i++)
02172         total_power += wfdata[i]*wfdata[i];
02173     } else {
02174       if(interleaved)
02175         for(int i=0; i<nelem; i++)
02176           total_power += wfdata[2*i]*wfdata[2*i];
02177       else 
02178         for(int i=0; i<nelem; i++)
02179           total_power += wfdata[i]*wfdata[i];
02180     }
02181     return(total_power);
02182   }
02183 
02184   template<class T, class U>
02185     diffractive_wavefront<T> & operator+=(diffractive_wavefront<T> & lhs_wf, const diffractive_wavefront<U> & rhs_wf) {
02186 
02187     if(lhs_wf.get_axes()!=rhs_wf.get_axes()){
02188       cerr << "operator+= error - mismatched arrays in diffractive_wavefronts\n";
02189       throw(string("diffractive_wavefront::operator+="));
02190     }
02191 
02192     lhs_wf.real_imag_conversion();
02193     rhs_wf.real_imag_conversion();
02194     if(lhs_wf.interleaved && !rhs_wf.interleaved) rhs_wf.interleaved_conversion();
02195     if(!lhs_wf.interleaved && rhs_wf.interleaved) rhs_wf.non_interleaved_conversion();
02196 
02197     int nelem = lhs_wf.diffractive_wavefront_header<T>::total_space();
02198     for(int i=0; i<2*nelem; i++)
02199       lhs_wf.wfdata[i] += rhs_wf.wfdata[i];
02200   
02201     return(lhs_wf);
02202   }
02203 
02204   template<class T, class U>
02205     diffractive_wavefront<T> & operator-=(diffractive_wavefront<T> & lhs_wf, const diffractive_wavefront<U> & rhs_wf) {
02206 
02207     if(lhs_wf.get_axes()!=rhs_wf.get_axes()){
02208       cerr << "operator-= error - mismatched arrays in diffractive_wavefronts\n";
02209       throw(string("diffractive_wavefront::operator-="));
02210     }
02211 
02212     lhs_wf.real_imag_conversion();
02213     rhs_wf.real_imag_conversion();
02214     if(lhs_wf.interleaved && !rhs_wf.interleaved) rhs_wf.interleaved_conversion();
02215     if(!lhs_wf.interleaved && rhs_wf.interleaved) rhs_wf.non_interleaved_conversion();
02216 
02217     int nelem = lhs_wf.diffractive_wavefront_header<T>::total_space();
02218     for(int i=0; i<2*nelem; i++) 
02219       lhs_wf.wfdata[i] -= rhs_wf.wfdata[i];
02220 
02221     return(lhs_wf);
02222   }
02223 
02224   template<class T, class U>
02225     diffractive_wavefront<T> & operator*=(diffractive_wavefront<T> & lhs_wf, const diffractive_wavefront<U> & rhs_wf) {
02226 
02227     if(lhs_wf.get_axes()!=rhs_wf.get_axes()){
02228       cerr << "operator*= error - mismatched arrays in diffractive_wavefronts\n";
02229       throw(string("diffractive_wavefront::operator*="));
02230     }
02231 
02232     lhs_wf.amp_phase_conversion();
02233     rhs_wf.amp_phase_conversion();
02234     if(lhs_wf.interleaved && !rhs_wf.interleaved) rhs_wf.interleaved_conversion();
02235     if(!lhs_wf.interleaved && rhs_wf.interleaved) rhs_wf.non_interleaved_conversion();
02236 
02237     // make sure that the diffractive_wavefronts are 
02238     // both interleaved or both not interleaved
02239     if(lhs_wf.interleaved) rhs_wf.interleaved_conversion();
02240     if(!lhs_wf.interleaved) rhs_wf.non_interleaved_conversion();
02241 
02242     int nelem = lhs_wf.diffractive_wavefront_header<T>::total_space();
02243     if(lhs_wf.interleaved){
02244       for(int i=0; i<nelem; i++){
02245         lhs_wf.wfdata[2*i] *= rhs_wf.wfdata[2*i];
02246         lhs_wf.wfdata[2*i+1] += rhs_wf.wfdata[2*i+1];
02247       }
02248     } else {
02249       for(int i=0; i<nelem; i++){
02250         lhs_wf.wfdata[i] *= rhs_wf.wfdata[i];
02251         lhs_wf.wfdata[i+nelem] += rhs_wf.wfdata[i+nelem];
02252       }
02253     }
02254 
02255     return(lhs_wf);
02256   }
02257 
02258   template<class T, class U>
02259     diffractive_wavefront<T> & operator/=(diffractive_wavefront<T> & lhs_wf, const diffractive_wavefront<U> & rhs_wf) {
02260 
02261     if(lhs_wf.get_axes()!=rhs_wf.get_axes()){
02262       cerr << "operator/= error - mismatched arrays in diffractive_wavefronts\n";
02263       throw(string("diffractive_wavefront::operator/="));
02264     }
02265 
02266     lhs_wf.amp_phase_conversion();
02267     rhs_wf.amp_phase_conversion();
02268     if(lhs_wf.interleaved) rhs_wf.interleaved_conversion();
02269     if(!lhs_wf.interleaved) rhs_wf.non_interleaved_conversion();
02270 
02271     int nelem = lhs_wf.diffractive_wavefront_header<T>::total_space();
02272     if(lhs_wf.interleaved){
02273       for(int i=0; i<nelem; i++){
02274         if(rhs_wf.wfdata[2*i] == 0) lhs_wf.wfdata[2*i] = 0;
02275         else lhs_wf.wfdata[2*i] /= rhs_wf.wfdata[2*i];
02276         lhs_wf.wfdata[2*i+1] += rhs_wf.wfdata[2*i+1];
02277       }
02278     } else {
02279       for(int i=0; i<nelem; i++){
02280         if(rhs_wf.wfdata[i] == 0) lhs_wf.wfdata[i] = 0;
02281         else lhs_wf.wfdata[i] /= rhs_wf.wfdata[i];
02282         lhs_wf.wfdata[i+nelem] -= rhs_wf.wfdata[i+nelem];
02283       }
02284     }
02285 
02286     return(lhs_wf);
02287   }
02288 
02289   template<class T>
02290     template<class U>
02291     diffractive_wavefront<T> & diffractive_wavefront<T>::operator+=(std::complex<U> c) {
02292 
02293     this->real_imag_conversion();
02294 
02295     int nelem = this->diffractive_wavefront_header<T>::total_space();
02296     double real = c.real();
02297     double imag = c.imag();
02298     if(interleaved){
02299       for(int i=0; i<nelem; i++){
02300         this->wfdata[2*i] += real;
02301         this->wfdata[2*i+1] += imag;
02302       }
02303     } else {
02304       for(int i=0; i<nelem; i++){
02305         this->wfdata[i] += real;
02306         this->wfdata[i+nelem] += imag;
02307       }
02308     }
02309 
02310     return(*this);
02311   }
02312 
02313   template<class T>
02314     template<class U>
02315     diffractive_wavefront<T> & diffractive_wavefront<T>::operator-=(std::complex<U> c) {
02316 
02317     this->real_imag_conversion();
02318 
02319     int nelem = this->diffractive_wavefront_header<T>::total_space();
02320     double real = c.real();
02321     double imag = c.imag();
02322     if(interleaved){
02323       for(int i=0; i<nelem; i++){
02324         this->wfdata[2*i] -= real;
02325         this->wfdata[2*i+1] -= imag;
02326       }
02327     } else {
02328       for(int i=0; i<nelem; i++){
02329         this->wfdata[i] -= real;
02330         this->wfdata[i+nelem] -= imag;
02331       }
02332     }
02333 
02334     return(*this);
02335   }
02336 
02337   template<class T>
02338     template<class U>
02339     diffractive_wavefront<T> & diffractive_wavefront<T>::operator*=(std::complex<U> c) {
02340 
02341     this->amp_phase_conversion();
02342 
02343     int nelem = this->diffractive_wavefront_header<T>::total_space();
02344     double abs_val = abs(c);
02345     double arg_val = arg(c);
02346     if(interleaved){
02347       for(int i=0; i<nelem; i++){
02348         this->wfdata[2*i] *= abs_val;
02349         this->wfdata[2*i+1] += arg_val;
02350       }
02351     } else {
02352       for(int i=0; i<nelem; i++){
02353         this->wfdata[i] *= abs_val;
02354         this->wfdata[i+nelem] += arg_val;
02355       }
02356     }
02357 
02358     return(*this);
02359   }
02360 
02361   template<class T>
02362     template<class U>
02363     diffractive_wavefront<T> & diffractive_wavefront<T>::operator/=(std::complex<U> c) {
02364 
02365     this->amp_phase_conversion();
02366 
02367     int nelem = this->diffractive_wavefront_header<T>::total_space();
02368     double abs = c.abs();
02369     double arg = c.arg();
02370     if(interleaved){
02371       for(int i=0; i<nelem; i++){
02372         if(abs==0) this->wfdata[2*i] = 0;
02373         else this->wfdata[2*i] /= abs;
02374         this->wfdata[2*i+1] -= arg;
02375       }
02376     } else {
02377       for(int i=0; i<nelem; i++){
02378         if(abs==0) this->wfdata[i] = 0;
02379         else this->wfdata[i] /= abs;
02380         this->wfdata[i+nelem] -= arg;
02381       }
02382     }
02383 
02384     return(*this);
02385   }
02386 
02387   template<class T, class U>
02388     diffractive_wavefront<T> operator+(const diffractive_wavefront<T> & wf1, const diffractive_wavefront<U> & wf2) {
02389     diffractive_wavefront<T> tmpwf(wf1);
02390     tmpwf+=wf2;
02391     return(tmpwf);
02392   }
02393 
02394   template<class T, class U>
02395     diffractive_wavefront<T> operator-(const diffractive_wavefront<T> & wf1, const diffractive_wavefront<U> & wf2) {
02396     diffractive_wavefront<T> tmpwf(wf1);
02397     tmpwf-=wf2;
02398     return(tmpwf);
02399   } 
02400 
02401   template<class T, class U>
02402     diffractive_wavefront<T> operator*(const diffractive_wavefront<T> & wf1, const diffractive_wavefront<U> & wf2) {
02403     diffractive_wavefront<T> tmpwf(wf1);
02404     tmpwf*=wf2;
02405     return(tmpwf);
02406   }
02407 
02408   template<class T, class U>
02409     diffractive_wavefront<T> operator/(const diffractive_wavefront<T> & wf1, const diffractive_wavefront<U> & wf2) {
02410     diffractive_wavefront<T> tmpwf(wf1);
02411     tmpwf/=wf2;
02412     return(tmpwf);
02413   }
02414 
02415   template<class T, class U>
02416     diffractive_wavefront<T> operator+(const diffractive_wavefront<T> & wf1, std::complex<U> c) {  
02417     diffractive_wavefront<T> tmpwf(wf1);
02418     tmpwf+=c;
02419     return(tmpwf);
02420   }
02421 
02422   template<class T, class U>
02423     diffractive_wavefront<T> operator-(const diffractive_wavefront<T> & wf1, std::complex<U> c) {  
02424     diffractive_wavefront<T> tmpwf(wf1);
02425     tmpwf-=c;
02426     return(tmpwf);
02427   }
02428 
02429   template<class T, class U>
02430     diffractive_wavefront<T> operator*(const diffractive_wavefront<T> & wf1, std::complex<U> c) {  
02431     diffractive_wavefront<T> tmpwf(wf1);
02432     tmpwf*=c;
02433     return(tmpwf);
02434   }
02435 
02436   template<class T, class U>
02437     diffractive_wavefront<T> operator/(const diffractive_wavefront<T> & wf1, std::complex<U> c) {  
02438     diffractive_wavefront<T> tmpwf(wf1);
02439     tmpwf/=c;
02440     return(tmpwf);
02441   }
02442 
02443   template<class T>
02444     bool operator !=(const diffractive_wavefront<T> & wf1, const diffractive_wavefront<T> & wf2) {
02445     return(!(wf1==wf2));
02446   }
02447 
02448 }
02449 
02450 #endif

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