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

refractive_atmospheric_layer.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 REFRACTIVE_ATMOSPHERIC_LAYER_H
00032 #define REFRACTIVE_ATMOSPHERIC_LAYER_H
00033 
00034 #include <iostream>
00035 #include <region_base.h>
00036 #include "power_spectrum.h"
00037 #include "pixel_array.h"
00038 #include "optic.h"
00039 #include "diffractive_wavefront.h"
00040 
00041 namespace Arroyo {
00042 
00043   using std::string;
00044   using std::vector;
00045   using std::ostream;
00046 
00047   template<typename U> class diffractive_wavefront;
00048   //class geometric_wavefront;
00049 
00053 
00054   template<class T>
00055   class refractive_atmospheric_layer :
00056     public plane_optic,
00057     public one_to_one_optic, 
00058     public pixel_array<T> {
00059 
00060     private:
00061 
00062     static const bool factory_registration;
00063 
00066     string unique_name() const {return(string("refractive atmospheric layer"));};
00067 
00068     protected:
00070     double pixel_scale;
00071 
00075     three_vector wind_vector;
00076 
00083     template<class U>
00084     void private_transform(diffractive_wavefront<U> & wf) const;
00085 
00096     template<class U>
00097     void aligned_private_transform(diffractive_wavefront<U> & wf) const;
00098 
00099     public:
00100 
00103     refractive_atmospheric_layer();
00104 
00107     refractive_atmospheric_layer(const refractive_atmospheric_layer<T> & ref_atm_layer);
00108 
00112     refractive_atmospheric_layer(const refractive_atmospheric_layer<T> & ref_atm_layer, 
00113                                  const rectangular_region & subregion);
00114 
00117     refractive_atmospheric_layer<T>(const char * filename);
00118 
00121     refractive_atmospheric_layer<T>(const iofits & iof);
00122 
00125     refractive_atmospheric_layer<T>(const pixel_array<T> & pixarr, 
00126                                     double pixel_scale);
00127 
00131     refractive_atmospheric_layer(const power_spectrum * pspectrum,
00132                                  const subharmonic_method & subm,
00133                                  const vector<long> & axes, 
00134                                  double pixscale);
00135 
00142     refractive_atmospheric_layer<T>(
00143                 const refractive_atmospheric_layer<T> & ref_atm_layer,
00144                 vector<three_point> & corners);
00145 
00148     ~refractive_atmospheric_layer(){};
00149 
00152     refractive_atmospheric_layer<T> & operator=(
00153                 const refractive_atmospheric_layer<T> & ref_atm_layer);
00154 
00157     void read(const char * filename);
00158 
00161     void read(const iofits & iof);
00162 
00165     void write(const char * filename) const;
00166 
00169     void write(iofits & iof) const;
00170 
00173     void print(ostream & os, const char * prefix="") const;
00174 
00187     rectangular_region get_covering_region(const three_frame & tf) const;
00188 
00191     virtual void transform(diffractive_wavefront<float> & wf) const;
00192 
00195     virtual void transform(diffractive_wavefront<double> & wf) const;
00196 
00199     //virtual void transform(geometric_wavefront & gwf) const;
00200 
00203     void rotate_by_fft(double angle, bool window=true);
00204 
00207     double get_pixel_scale() const {return(pixel_scale);};
00208 
00211     void set_pixel_scale(double pscale) {pixel_scale = pscale;};
00212 
00215     vector<long> get_axes() const {return(this->axes);};
00216 
00221     void set_axes(const vector<long> & in_axes);
00222 
00225     three_vector get_wind_vector() const {return(wind_vector);};
00226 
00229     void set_wind_vector(const three_vector & wvec) {wind_vector = wvec;};
00230 
00231   };
00232 
00233   template<class T>
00234   refractive_atmospheric_layer<T>::refractive_atmospheric_layer() {
00235     pixel_scale = 0;
00236   }
00237 
00238   template<class T>
00239   refractive_atmospheric_layer<T>::
00240   refractive_atmospheric_layer(
00241         const refractive_atmospheric_layer<T> & ref_atm_layer){
00242     this->operator=(ref_atm_layer);
00243   }
00244 
00245   template<class T>
00246   refractive_atmospheric_layer<T>::
00247   refractive_atmospheric_layer(
00248                 const refractive_atmospheric_layer<T> & ref_atm_layer, 
00249                 const rectangular_region & subregion) {
00250 
00251     rectangular_region arg_layer_region(ref_atm_layer, 
00252                                         ref_atm_layer.get_axes(), 
00253                                         ref_atm_layer.get_pixel_scale());
00254 
00255     if(!subregion.aligned(arg_layer_region)){
00256       cerr << "refractive_atmospheric_layer::refractive_atmospheric_layer error - "
00257            << "regions not aligned\n";
00258       subregion.print(cerr, "this region ");
00259       arg_layer_region.print(cerr, "arg region  ");
00260       throw(string("refractive_atmospheric_layer::refractive_atmospheric_layer"));
00261     }
00262     
00263     if(!arg_layer_region.contains(subregion)){
00264       cerr << "refractive_atmospheric_layer::refractive_atmospheric_layer error - "
00265            << "requested region not contained in layer\n";
00266       subregion.print(cerr, "subregion ");
00267       arg_layer_region.print(cerr, "arg region  "); 
00268       throw(string("refractive_atmospheric_layer::refractive_atmospheric_layer"));
00269     }
00270    
00271     // Enlarge subregion so that it is an even number of pixels
00272     // in size.
00273     rectangular_region integral_pixel_subregion(subregion,
00274                                         ref_atm_layer.get_pixel_scale());
00275 
00276     // Find the subpixel shift between the two regions
00277     three_point arg_layer_center = arg_layer_region.get_center();
00278     three_point integral_pixel_subregion_center =
00279                                 integral_pixel_subregion.get_center();
00280 
00281     three_vector delta_center =
00282                         integral_pixel_subregion_center - arg_layer_center;
00283 
00284     double delta_center_length = delta_center.length();
00285     three_vector subpixel_shift;
00286     if(delta_center_length>three_frame::precision) {
00287       subpixel_shift = 
00288         (fmod(delta_center_length, ref_atm_layer.get_pixel_scale()) / 
00289          delta_center_length)*delta_center;
00290     }
00291 
00292     // zero out the subpixel shift if components are less than the limiting precision
00293     if(fabs(subpixel_shift.x(ref_atm_layer))<three_frame::precision)
00294       subpixel_shift = three_vector(0, subpixel_shift.y(ref_atm_layer),
00295                         0, ref_atm_layer);
00296     if(fabs(subpixel_shift.y(ref_atm_layer))<three_frame::precision)
00297       subpixel_shift = three_vector(subpixel_shift.x(ref_atm_layer),
00298                         0, 0, ref_atm_layer);
00299 
00300     if(optic::verbose_level)
00301       cout << "refractive_atmospheric_layer::refractive_atmospheric_layer - "
00302            << "subpixel_shift "
00303            << subpixel_shift.x(ref_atm_layer) << "\t"
00304            << subpixel_shift.y(ref_atm_layer) << endl;
00305 
00306     // Get the corners of the region that we will extract
00307     vector<three_point> integral_pixel_subregion_corners =
00308                         integral_pixel_subregion.get_corners();
00309     for(int i=0; i<4; i++)
00310       integral_pixel_subregion_corners[i] -= subpixel_shift;
00311 
00312     // Construct a frame of reference centered at the corner of the arg layer
00313     double pixscale = ref_atm_layer.get_pixel_scale();
00314     vector<long> arg_layer_axes = ref_atm_layer.get_axes();
00315     three_vector corner_vec(pixscale*arg_layer_axes[0]/2.0, 
00316                             pixscale*arg_layer_axes[1]/2.0, 
00317                             0, ref_atm_layer);
00318     three_translation ttrans(corner_vec);
00319     three_frame local_frame(ref_atm_layer);
00320     ttrans.transform(local_frame);
00321 
00322     // Find the limiting pixel coordinates of the subregion
00323     vector<long> coord_limits(4);
00324     coord_limits[0] = coord_limits[1] = 
00325       (long)(ceil(integral_pixel_subregion_corners[0].x(local_frame)/pixscale));
00326     coord_limits[2] = coord_limits[3] = 
00327       (long)(ceil(integral_pixel_subregion_corners[0].y(local_frame)/pixscale));
00328     long tx, ty;
00329     for(int i=1; i<4; i++){
00330       tx = (long)(ceil(integral_pixel_subregion_corners[i].x(local_frame)/pixscale));
00331       ty = (long)(ceil(integral_pixel_subregion_corners[i].y(local_frame)/pixscale));
00332       if(tx<coord_limits[0]) coord_limits[0] = tx;
00333       if(tx>coord_limits[1]) coord_limits[1] = tx;
00334       if(ty<coord_limits[2]) coord_limits[2] = ty;
00335       if(ty>coord_limits[3]) coord_limits[3] = ty;
00336     }
00337 
00338     if(optic::verbose_level)
00339       cout << "refractive_atmospheric_layer::refractive_atmospheric_layer - "
00340            << "extracting range "
00341            << coord_limits[0] << " - " << coord_limits[1] << "  "
00342            << coord_limits[2] << " - " << coord_limits[3] << endl;
00343 
00344     // extract the appropriate subregion and perform the shift by fft to account
00345     // for the non integral shift
00346     this->pixel_array<T>::operator=(pixel_array<T>(ref_atm_layer,coord_limits));
00347     this->shift_by_fft(subpixel_shift.x(local_frame),
00348                                 subpixel_shift.y(local_frame));
00349 
00350     // fix up the three_frame of the layer so that its origin
00351     // is in the center of the new subregion
00352     this->three_point::operator=(subregion.get_center());
00353 
00354     // and finally the pixel scale
00355     this->pixel_scale = pixscale;    
00356   }
00357 
00358   template<class T>
00359   refractive_atmospheric_layer<T>::
00360   refractive_atmospheric_layer(const char * filename){
00361     iofits iof;
00362     try{iof.open(filename);}
00363     catch(...){
00364       cerr << "refractive_atmospheric_layer::refractive_atmospheric_layer - "
00365            << "error opening file " << filename << endl;
00366       throw(string("refractive_atmospheric_layer::refractive_atmospheric_layer"));
00367     }
00368     this->read(iof);
00369   } 
00370 
00371   template<class T>
00372   refractive_atmospheric_layer<T>::refractive_atmospheric_layer(const iofits & iof){
00373     this->read(iof);
00374   } 
00375 
00376   template<class T>
00377   refractive_atmospheric_layer<T>::
00378   refractive_atmospheric_layer(const refractive_atmospheric_layer & ref_atm_layer, 
00379                                vector<three_point> & corners) {
00380     pixel_scale = ref_atm_layer.pixel_scale;
00381     wind_vector = ref_atm_layer.wind_vector;
00382     this->three_frame::operator=(ref_atm_layer);
00383   }
00384 
00385   template<class T>
00386   refractive_atmospheric_layer<T>::
00387   refractive_atmospheric_layer(const pixel_array<T> & pixarr, 
00388                                double pixscale)
00389     :  pixel_array<T>(pixarr) {
00390 
00391     if(pixarr.get_axes().size()!=2){
00392       cerr << "refractive_atmospheric_layer::refractive_atmospheric_layer error - "
00393            << "cannot allocate layer with dimension "
00394            << pixarr.get_axes().size() << endl;
00395       throw(string("refractive_atmospheric_layer::refractive_atmospheric_layer"));
00396     }
00397     pixel_scale = pixscale;
00398   }
00399 
00400   template<class T>
00401   refractive_atmospheric_layer<T> & refractive_atmospheric_layer<T>::
00402   operator=(const refractive_atmospheric_layer<T> & ref_atm_layer){
00403     if(this==&ref_atm_layer)
00404       return(*this);
00405 
00406     pixel_scale = ref_atm_layer.pixel_scale;
00407     wind_vector = ref_atm_layer.wind_vector;
00408     this->plane_optic::operator=(ref_atm_layer);
00409     this->pixel_array<T>::operator=(ref_atm_layer);
00410     return(*this);
00411   }
00412 
00413   template<class T>
00414   refractive_atmospheric_layer<T>::
00415     refractive_atmospheric_layer(const power_spectrum * pspectrum,
00416                                  const subharmonic_method & subm,
00417                                  const vector<long> & axes, 
00418                                  double pixscale){
00419 
00420     if(axes.size()!=2){
00421       cerr << "refractive_atmospheric_layer<T>::refractive_atmospheric_layer error - "
00422            << "cannot construct refractive atmospheric layer with "
00423            << axes.size() << "axes\n";
00424       throw(string("refractive_atmospheric_layer<T>::refractive_atmospheric_layer"));
00425     }
00426 
00427     for(int i=0; i<axes.size(); i++){
00428       if(axes[i]<=0){
00429         cerr << "refractive_atmospheric_layer<T>::"
00430              << "refractive_atmospheric_layer error - "
00431              << " axis " << i << " has value " << axes[i] 
00432              << ", which is less than zero - can't make a "
00433              << "refractive atmospheric layer with this dimension\n";
00434         throw(string("refractive_atmospheric_layer<T>::refractive_atmospheric_layer"));
00435       }
00436     }
00437 
00438     if(pixscale<=0){
00439       cerr << "refractive_atmospheric_layer<T>::refractive_atmospheric_layer error -\n"
00440            << "invalid pixel scale " << pixscale << endl;
00441       throw(string("refractive_atmospheric_layer<T>::refractive_atmospheric_layer"));
00442     }
00443 
00444     // This is a temporary trick to force the
00445     // computation to always occur on axes suitable for
00446     // the subharmonic method
00447     vector<long> working_axes = axes;
00448     if(subm.intrinsic_dimensionality()!=-1){
00449       if(working_axes[0]%2!=subm.intrinsic_dimensionality()) working_axes[0]++;
00450       if(working_axes[1]%2!=subm.intrinsic_dimensionality()) working_axes[1]++;
00451     } 
00452 
00453     T * data;
00454     //try{data = new T[2*working_axes[1]*working_axes[0]];}
00455     alloc_size sz(working_axes[0], working_axes[1], 2);
00456     try{
00457       data = new T[sz];
00458     }
00459     catch(...){
00460       cerr << "refractive_atmospheric_layer<T>::refractive_atmospheric_layer error - "
00461            << "unable to allocate memory: " << sz << " bytes\n";
00462       throw;
00463     }
00464 
00465     initialize_frequency_array<T>(data, pspectrum, working_axes, pixscale, true, subm);
00466 
00467     fft_manager<T> fft_mgr;
00468     halfpixel_fft<T>(working_axes, data, fft_mgr);
00469 
00470     // Nominally we're losing half the effort here.
00471     // It would be better to try to do a real to complex
00472     // fft, but it is not so easy to get it right.
00473     for(int i=0; i<working_axes[1]; i++)
00474       for(int j=0; j<working_axes[0]; j++)
00475         data[i*working_axes[0]+j] = data[2*(i*working_axes[0]+j)];
00476 
00477     // Sort the data back into the original axes
00478     if(axes!=working_axes){
00479       for(int i=0; i<axes[1]; i++)
00480         for(int j=0; j<axes[0]; j++)
00481           data[i*axes[0]+j] = data[i*working_axes[0]+j];
00482     }
00483 
00484     pixel_array<T> pixarr(axes, data);
00485     delete [] data; 
00486     this->operator=(refractive_atmospheric_layer<T>(pixarr, pixscale));
00487   }
00488 
00489   template<class T>
00490   void refractive_atmospheric_layer<T>::set_axes(const vector<long> & in_axes){
00491     if(in_axes.size()!=2){
00492       cerr << "refractive_atmospheric_layer::set_axes error - "
00493            << "cannot set axes to dimension "
00494            << in_axes.size() << " - must be 2 dimensional\n";
00495       throw(string("refractive_atmospheric_layer::set_axes"));
00496     }
00497     pixel_array<T>::set_axes(in_axes);
00498   }
00499 
00500   template<class T>
00501   void refractive_atmospheric_layer<T>::read(const char * filename){
00502     iofits iof;
00503     try{iof.open(filename);}
00504     catch(...){
00505       cerr << "refractive_atmospheric_layer::read - "
00506            << "error opening file " << filename << endl;
00507       throw(string("refractive_atmospheric_layer::read"));
00508     }
00509     try{this->read(iof);}
00510     catch(...){
00511       cerr << "refractive_atmospheric_layer::read - "
00512            << "error reading "
00513            << this->unique_name() << " from file "
00514            << filename << endl;
00515       throw(string("refractive_atmospheric_layer::read"));
00516     }
00517   }
00518 
00519   template<class T>
00520   void refractive_atmospheric_layer<T>::read(const iofits & iof){
00521 
00522     if(!iof.key_exists("TYPE")){
00523       cerr << "refractive_atmospheric_layer::read error - "
00524            << "unrecognized type of file\n";
00525       iof.print_header(cerr, "hdr dump");
00526       cerr << "hdu num " << iof.get_hdu_num() << " of "
00527            << iof.get_num_hdus() << endl;
00528       throw(string("refractive_atmospheric_layer::read"));
00529     }
00530     string type, comment;
00531     iof.read_key("TYPE", type, comment);
00532     if(type!=this->unique_name()){
00533       cerr << "refractive_atmospheric_layer::read error - file of type " 
00534            << type << " rather than of type "
00535            << this->unique_name() << endl;
00536       throw(string("refractive_atmospheric_layer::read"));
00537     }
00538 
00539     iof.read_key("PIXSCALE", pixel_scale, comment);
00540     wind_vector.read(iof);
00541     this->plane_optic::read(iof);
00542 
00543     this->pixel_array<T>::read(iof);
00544 
00545     if(iof.get_hdu_num()<iof.get_num_hdus())
00546       iof.movrel_hdu(1);
00547   }
00548 
00549   template<class T>
00550   void refractive_atmospheric_layer<T>::write(const char * filename) const {
00551     iofits iof;
00552     try{iof.create(filename);}
00553     catch(...){
00554       cerr << "refractive_atmospheric_layer::write - "
00555            << "error opening file " << filename << endl;
00556       throw(string("refractive_atmospheric_layer::write"));
00557     }
00558     try{this->write(iof);}
00559     catch(...){
00560       cerr << "refractive_atmospheric_layer::write - "
00561            << "error writing " 
00562            << this->unique_name() << " to file "
00563            << filename << endl;
00564       throw(string("refractive_atmospheric_layer::write"));
00565     }
00566   }
00567 
00568   template<class T>
00569   void refractive_atmospheric_layer<T>::write(iofits & iof) const {
00570 
00571     fits_header_data<double> fhd(this->get_axes());
00572     fhd.write(iof);
00573     string type = this->unique_name();
00574     string comment = "object type";
00575     iof.write_key("TYPE", type, comment);
00576     type = "pixel scale (meters)";
00577     iof.write_key("PIXSCALE", pixel_scale, type);
00578     wind_vector.write(iof);
00579     this->plane_optic::write(iof);
00580     this->pixel_array<T>::write(iof);
00581   }
00582 
00583   template<class T>
00584   void refractive_atmospheric_layer<T>::
00585   print(ostream & os, const char * prefix) const {
00586     int vlspc = 30;
00587     os.setf(ios::left, ios::adjustfield); 
00588     os << prefix << "TYPE       = " << setw(vlspc) << this->unique_name()
00589        << "/" << "object type" << endl;
00590     fits_header_data<double> fhd(this->get_axes());
00591     fhd.print(os, prefix);
00592     os << prefix << "PIXSCALE   = " << setw(vlspc) << pixel_scale
00593        << "/" << "pixel scale (meters)" << endl;
00594     three_frame tf;
00595     wind_vector.print(os, tf, prefix);
00596     this->plane_optic::print(cout, prefix);
00597   }
00598 
00599   template<class T>
00600   void refractive_atmospheric_layer<T>::rotate_by_fft(double angle, bool window){
00601     this->pixel_array<T>::rotate_by_fft(angle, window);
00602     three_rotation trot(*this, this->z(), -angle);
00603     trot.transform(*this);
00604   }
00605 
00606   template<class T>
00607   rectangular_region
00608   refractive_atmospheric_layer<T>::get_covering_region(
00609                                         const three_frame & tf) const {
00610 
00611     // This is the same code as
00612     // rectangular_region::get_covering_region - you could consolidate
00613     // it...
00614 
00615     if(fabs(dot_product(tf.z(), this->z()))<three_frame::precision){
00616       cerr << "refractive_atmospheric_layer::get_covering_region error - "
00617            << "z axes of this aperture and three frame provided "
00618            << "to this function are orthogonal\n";
00619       throw(string("refractive_atmospheric_layer::get_covering_region"));
00620     }
00621 
00622     vector<double> size(2, pixel_scale*this->axes[0]);
00623     size[1] = pixel_scale*this->axes[1];
00624 
00625     vector<three_point> tp(4);
00626     tp[0] = *this + .5*size[0]*this->x() + .5*size[1]*this->y();
00627     tp[1] = *this - .5*size[0]*this->x() + .5*size[1]*this->y();
00628     tp[2] = *this - .5*size[0]*this->x() - .5*size[1]*this->y();
00629     tp[3] = *this + .5*size[0]*this->x() - .5*size[1]*this->y();
00630 
00631     if(foreshortening){
00632       // project off the component along tf.z() to get
00633       // a three point in the XY plane of tf
00634       int aligned = 1;
00635       if(dot_product(this->z(), tf.z())<1) aligned = -1;
00636       for(int i=0; i<4; i++)
00637         tp[i] -= aligned*dot_product(tp[i]-*this, tf.z())*tf.z();
00638     } else {
00639       three_vector rotation_axis = cross_product(this->z(), tf.z());
00640       if(rotation_axis.length() > three_frame::precision){
00641         three_rotation trot(*this, rotation_axis, rotation_axis.length());
00642         for(int i=0; i<4; i++)
00643           trot.transform(tp[i]);
00644       }
00645     }
00646     
00647     // Next we find the extremal coordinates of the points identified above
00648     // in the three_frame tf
00649     double xmin = tp[0].x(tf);
00650     double xmax = xmin;
00651     double ymin = tp[0].y(tf);
00652     double ymax = ymin;
00653     for(int i=1; i<4; i++){
00654       if(tp[i].x(tf)>xmax) xmax = tp[i].x(tf);
00655       if(tp[i].x(tf)<xmin) xmin = tp[i].x(tf);
00656       if(tp[i].y(tf)>ymax) ymax = tp[i].y(tf);
00657       if(tp[i].y(tf)<ymin) ymin = tp[i].y(tf);
00658     }
00659     
00660     // Finally we make a rectangular region from these limiting coordinates
00661     tp[0] = three_point(xmin, ymin, 0, tf);
00662     tp[1] = three_point(xmax, ymin, 0, tf);
00663     tp[2] = three_point(xmax, ymax, 0, tf);
00664     tp[3] = three_point(xmin, ymax, 0, tf);
00665     return(rectangular_region(tp));
00666     
00667   }
00668 
00669   template<class T>
00670   void refractive_atmospheric_layer<T>::transform(
00671                         diffractive_wavefront<float> & wf) const {
00672     try{this->private_transform(wf);}
00673     catch(...){
00674       cerr << "refractive_atmospheric_layer::transform error - "
00675            << "error transforming a float instantiation of "
00676            << "diffractive_wavefront\n";
00677       throw(string("refractive_atmospheric_layer::transform"));
00678     }
00679   }
00680 
00681   template<class T>
00682   void refractive_atmospheric_layer<T>::transform(
00683                         diffractive_wavefront<double> & wf) const {
00684     try{this->private_transform(wf);}
00685     catch(...){
00686       cerr << "refractive_atmospheric_layer::transform error - "
00687            << "error transforming a float instantiation "
00688            << "of diffractive_wavefront\n";
00689       throw(string("refractive_atmospheric_layer::transform"));
00690     }
00691   }
00692 
00693   template<class T> template<class U>
00694   void refractive_atmospheric_layer<T>::private_transform(
00695                         diffractive_wavefront<U> & wf) const {
00696 
00697     // This frame will represent the wavefront frame for the transformation.
00698     // If foreshortening is off, this frame is different than the true
00699     // wavefront frame
00700     three_frame wf_frame(wf);
00701     if(!foreshortening){
00702       three_vector rotation_axis = cross_product(this->z(), wf.z());
00703       if(rotation_axis.length()>three_frame::precision){
00704         three_rotation trot(wf, rotation_axis, rotation_axis.length());
00705         trot.transform(wf_frame);
00706       }
00707     }
00708 
00709     // If the transverse axes are aligned, we can call
00710     //   aligned_private_transform directly
00711     if(fabs(dot_product(wf_frame.x(), this->y()))<three_frame::precision && 
00712        fabs(dot_product(wf_frame.y(), this->x()))<three_frame::precision){
00713       if(optic::verbose_level)
00714         cerr << "refractive_atmospheric_layer::private_transform"
00715              << " - calling aligned_private_transform directly...";
00716       try{this->aligned_private_transform(wf);}
00717       catch(...){
00718         cerr << "refractive_atmospheric_layer::private_transform error - "
00719              << "could not perform transform\n";
00720         throw(string("refractive_atmospheric_layer::private_transform"));
00721       }
00722       if(optic::verbose_level) cout << "returning\n";
00723       return;      
00724     }
00725 
00726     // Otherwise, we have to construct a layer with the above property
00727     // by extracting the minimal part of the layer and rotating it to 
00728     // align with the wavefront axes.
00729 
00730     // Ensure that at least one basis vector of the wavefront frame
00731     // lies in the plane of the layer.  In this way we can rotate the
00732     // layer about its z axis so that it is aligned with this axis.
00733     // Then the wf pixels projected onto the plane of the layer will
00734     // be rectangles rather than parallelograms, and we can call the 
00735     // aligned_private_transform function.
00736     double dot_xz = dot_product(wf_frame.x(), this->z());
00737     double dot_yz = dot_product(wf_frame.y(), this->z());
00738     if(fabs(dot_xz)>three_frame::precision
00739                                 && fabs(dot_yz)>three_frame::precision){
00740       cerr << "refractive_atmospheric_layer::private_transform error - "
00741            << "at least one of the transverse axes of the wavefront must lie "
00742            << "in the plane of the layer.\n";
00743       wf_frame.three_frame::print(cerr, "wf three_frame ");
00744       this->three_frame::print(cerr, "layer three_frame ");
00745       throw(string("refractive_atmospheric_layer::private_transform"));
00746     }
00747 
00748     // Here we define the rotation angle as negative because
00749     // we are in essence doing a passive rotation - rotating
00750     // the pixel frame rather than the image itself
00751     double rotation_angle;
00752     if(fabs(dot_xz)<three_frame::precision)
00753       rotation_angle = -acos(dot_product(wf_frame.x(), this->x()));
00754     else
00755       rotation_angle = -acos(dot_product(wf_frame.y(), this->y()));
00756 
00757     // Compute the size of the wavefront projected onto the plane of the
00758     // layer
00759 
00760     // If foreshortening is on, we need to account for this.
00761     // If the z axes of the wf is not aligned with that of the layer,
00762     // project the wf region into the transverse plane of the layer.
00763     rectangular_region wf_region(*this, wf.get_axes(), wf.get_pixel_scale());
00764     if(this->foreshortening){
00765       wf_region = rectangular_region(wf_frame, wf.get_axes(),
00766                                                 wf.get_pixel_scale());
00767       wf_region = rectangular_region(wf_region, this->z(), false);
00768     } 
00769 
00770     vector<three_point> wf_projected_corners = wf_region.get_corners();
00771 
00772     // The wavefront projected into the plane of the layer is a
00773     // rectangular region whose edges are not necessarily aligned with
00774     // the axes of the layer.  We need to find the minimal rectangular
00775     // region that contains the projected wavefront and whose edges
00776     // are aligned with the axes of the layer.  To do so, we just 
00777     // get the extremal coordinates of the wf_projected_corners in 
00778     // the frame of the layer.
00779     double x_min = wf_projected_corners[0].x(*this);
00780     double x_max = x_min;
00781     double y_min = wf_projected_corners[0].y(*this);
00782     double y_max = y_min;
00783     double tmp;
00784     for(int i=1; i<4; i++){
00785       tmp = wf_projected_corners[i].x(*this);
00786       if(tmp<x_min) x_min = tmp;
00787       if(tmp>x_max) x_max = tmp;
00788       tmp = wf_projected_corners[i].y(*this);
00789       if(tmp<y_min) y_min = tmp;
00790       if(tmp>y_max) y_max = tmp;
00791     }
00792 
00793     // Get the corner coordinates of the region we'll extract.
00794     // Here we have to account for the wind, so we shift the 
00795     // layer_extraction corners by the wind vector.
00796     three_vector wind_vector = wf.get_timestamp()*this->get_wind_vector();
00797 
00798     vector<three_point> layer_extraction_corners(4);
00799     layer_extraction_corners[0] =
00800                 three_point(x_min, y_min, 0, *this) - wind_vector;
00801     layer_extraction_corners[1] =
00802                 three_point(x_max, y_min, 0, *this) - wind_vector;
00803     layer_extraction_corners[2] =
00804                 three_point(x_max, y_max, 0, *this) - wind_vector;
00805     layer_extraction_corners[3] =
00806                 three_point(x_min, y_max, 0, *this) - wind_vector;
00807 
00808     rectangular_region layer_extraction_region(layer_extraction_corners);
00809 
00810     // Finally, we extract this region, rotate it about its center,
00811     // and extract a final region that is of the same size as the 
00812     // projected wavefront.  We may then call aligned_private_transform 
00813     // using this layer.
00814     refractive_atmospheric_layer<T> xtrctd_layer(*this, layer_extraction_region);
00815     xtrctd_layer.rotate_by_fft(rotation_angle, false);
00816     xtrctd_layer.aligned_private_transform(wf);
00817   }
00818 
00819   /*
00820   template<class T> template<class U>
00821   void refractive_atmospheric_layer<T>::aligned_private_transform(
00822                                 diffractive_wavefront<U> & wf) const {
00823 
00824     // First, ensure that the center of this wavefront lies in the
00825     // plane of the layer
00826     if(operator!=(static_cast<three_point>(wf),
00827                                 static_cast<three_point>(*this))){
00828       three_vector origin_offset = 
00829         static_cast<three_point>(wf) - static_cast<three_point>(*this);
00830     
00831       if(fabs(dot_product(origin_offset,
00832                         this->three_frame::z()))>three_frame::precision){
00833         cerr << "refractive_atmospheric_layer::aligned_private_transform error - "
00834              << "diffractive_wavefront center not in transverse plane of layer\n";
00835         wf.three_point::print(cerr, *this, "wavefront center in frame of layer ");
00836         throw(string("refractive_atmospheric_layer::aligned_private_transform"));
00837       }
00838     }
00839     
00840     // Verify that the transverse axes are aligned. 
00841     // This check is valid regardless of the foreshortening
00842     // status.
00843     if(fabs(dot_product(wf.x(), this->y()))>three_frame::precision &&
00844        fabs(dot_product(wf.y(), this->x()))<three_frame::precision){
00845       cerr << "refractive_atmospheric_layer::aligned_private_transform error - "
00846            << "the wavefront transverse axes are not aligned "
00847            << "with those of the layer\n";
00848       throw(string("refractive_atmospheric_layer::aligned_private_transform"));
00849     }
00850 
00851     three_frame wind_blown_frame(*this);
00852     wind_blown_frame += wf.get_timestamp()*this->get_wind_vector();
00853 
00854     // Verify that the wavefront is fully contained by the layer.
00855     rectangular_region *layer_region, *wf_region, *modified_wf_region;
00856 
00857     try{
00858       layer_region = new rectangular_region(wind_blown_frame,
00859                                             this->get_axes(), this->get_pixel_scale());
00860     } catch(...) {
00861       cerr << "refractive_atmospheric_layer::aligned_private_transform error - "
00862            << "could not get layer region\n";
00863       throw(string("refractive_atmospheric_layer::aligned_private_transform"));
00864     }
00865 
00866     try{
00867       wf_region = new rectangular_region(wf, wf.get_axes(), wf.get_pixel_scale());
00868     } catch(...) {
00869       cerr << "refractive_atmospheric_layer::aligned_private_transform error - "
00870            << "could not get layer region\n";
00871       throw(string("refractive_atmospheric_layer::aligned_private_transform"));
00872     }
00873 
00874     if(this->foreshortening){
00875       modified_wf_region = new rectangular_region(*wf_region, this->z(), false);
00876     } else {
00877       three_frame tmp_frame;
00878       if(dot_product(wf.z(), this->z())>0)
00879         tmp_frame = three_frame(wf, this->x(), this->y(), this->z());
00880       else 
00881         tmp_frame = three_frame(wf, this->x(), this->y(), -1*this->z());
00882       modified_wf_region = new rectangular_region(tmp_frame,
00883                                 wf.get_axes(), wf.get_pixel_scale());
00884     }
00885 
00886     try{
00887       if(!layer_region->contains(*modified_wf_region)){
00888         throw(string(""));
00889       }
00890     } catch(...) {
00891       cerr << "refractive_atmospheric_layer::aligned_private_transform error - "
00892            << "layer does not contain wavefront\n";
00893       layer_region->print(cerr, "layer region ");
00894       modified_wf_region->print(cerr, "wfrnt region ");
00895       throw(string("refractive_atmospheric_layer::aligned_private_transform"));
00896     }
00897 
00898     delete layer_region, wf_region, modified_wf_region;
00899 
00900     // the half pixel definitions - so that
00901     // when you have even axes the pixel
00902     // centroids lie on half pixel values.
00903     vector<long> wf_axes = wf.get_axes();
00904     double wf_x_halfpix=0, wf_y_halfpix=0;
00905     double layer_x_halfpix=0, layer_y_halfpix=0;
00906     int wf_x_extrapix=1, wf_y_extrapix=1;
00907     int layer_x_extrapix=1, layer_y_extrapix=1;
00908     if(wf_axes[1]%2==0){
00909       wf_x_halfpix = .5;
00910       wf_x_extrapix = 0;
00911     }
00912     if(wf_axes[0]%2==0){
00913       wf_y_halfpix = .5;
00914       wf_y_extrapix = 0;
00915     }
00916     if(this->axes[1]%2==0){
00917       layer_x_halfpix = .5;
00918       layer_x_extrapix = 0;
00919     }
00920     if(this->axes[0]%2==0){
00921       layer_y_halfpix = .5;
00922       layer_y_extrapix = 0;
00923     }
00924  
00925     // Finally, we are ready to run through the arrays adding the layer
00926     // to the wavefront.  If foreshortening is on the pixel scale of the
00927     // wavefront may differ in the x and y direction, due to the
00928     // projection effect.  Here we define some quantities to specify the
00929     // wf pixel scales
00930     double wf_x_pixscale = wf.get_pixel_scale();
00931     double wf_y_pixscale = wf.get_pixel_scale();
00932     double dp;
00933     if(this->get_foreshortening()){
00934       dp = dot_product(wf.x(), this->x());
00935       wf_x_pixscale /= (dp*dp);
00936       dp = dot_product(wf.y(), this->y());
00937       wf_y_pixscale /= (dp*dp);
00938       if(optic::verbose_level)
00939         cout << "refractive_atmospheric_layer::aligned_private_transform -\n"
00940              << "\twavefront pixel scale " << wf.get_pixel_scale() << endl
00941              << "\tprojected x pixel scale " << wf_x_pixscale << endl
00942              << "\tprojected y pixel scale " << wf_y_pixscale << endl;
00943     }
00944 
00945     // Convert the wavefront to amplitude and phase.  In this way
00946     // we can add in the phase from the layer OPD and it won't wrap
00947     this->wavefront_amp_phase_conversion(wf);
00948     U * wfdata = this->get_wavefront_data(wf);
00949 
00950     // Next, for each pixel in the wavefront, we are going to average
00951     // over the pixels in the layer that are contained by the wavefront
00952     // pixel.  If there are layer pixels that partially overlap the
00953     // wavefront pixel, we'll downweight them by their areal overlap.
00954 
00955     double wf_wavelength = wf.get_wavelength();
00956     double wf_x_pixel_coord, wf_y_pixel_coord;
00957     double tmp_wf_x_pixel_coord, tmp_wf_y_pixel_coord;
00958     double max_wf_x_pixel_coord, max_wf_y_pixel_coord;
00959     double area, refractive_optical_path;
00960     three_vector origin_offset = wf - wind_blown_frame;
00961     bool is_real_imag = this->is_real_imag_storage(wf);
00962     bool is_interleaved = this->is_interleaved_storage(wf);
00963     double tmp, cp, sp;
00964     int index, wf_nelem = wf_axes[0]*wf_axes[1],
00965       layer_nelem = this->axes[0]*this->axes[1];
00966 
00967     for(int i=-wf_axes[1]/2; i<wf_axes[1]/2+wf_x_extrapix; i++){
00968       for(int j=-wf_axes[0]/2; j<wf_axes[0]/2+wf_y_extrapix; j++){
00969 
00970       
00971         // These are the coordinates of the lower corner of the wf pixel
00972         // in the wind blown frame, measured in units of the layer pixel scale.
00973         wf_x_pixel_coord = ((j+wf_x_halfpix-.5)*wf_x_pixscale + 
00974                             origin_offset.x(wind_blown_frame))/this->pixel_scale;
00975         wf_y_pixel_coord = ((i+wf_y_halfpix-.5)*wf_y_pixscale + 
00976                             origin_offset.y(wind_blown_frame))/this->pixel_scale;
00977 
00978 
00979         // These are the coordinates of the upper corner of the wf pixel
00980         // in the wind blown frame, measured in units of the layer pixel scale.
00981         max_wf_x_pixel_coord =
00982                         wf_x_pixel_coord + wf_x_pixscale/this->pixel_scale;
00983         max_wf_y_pixel_coord =
00984                         wf_y_pixel_coord + wf_y_pixscale/this->pixel_scale;
00985         
00986         // These are the coordinates of the upper corner of the layer
00987         // pixel in the wind blown frame, measured in units of the layer
00988         // pixel scale.  
00989         //
00990         // If the lower corner of the wf pixel happens to lie on a layer
00991         // pixel boundary, then ceil() won't change the values and so we
00992         // make sure to explicitly increment these.
00993         tmp_wf_x_pixel_coord = ceil(wf_x_pixel_coord);
00994         if(fabs(tmp_wf_x_pixel_coord-wf_x_pixel_coord)<three_frame::precision)
00995           tmp_wf_x_pixel_coord++;
00996         tmp_wf_y_pixel_coord = ceil(wf_y_pixel_coord);
00997         if(fabs(tmp_wf_y_pixel_coord-wf_y_pixel_coord)<three_frame::precision)
00998           tmp_wf_y_pixel_coord++;
00999 
01000         refractive_optical_path = 0;
01001         area = 0;
01002 
01003         while(wf_x_pixel_coord < max_wf_x_pixel_coord){
01004 
01005           if(tmp_wf_x_pixel_coord > max_wf_x_pixel_coord)
01006             tmp_wf_x_pixel_coord = max_wf_x_pixel_coord;
01007           
01008           while(wf_y_pixel_coord < max_wf_y_pixel_coord){
01009           
01010             if(tmp_wf_y_pixel_coord > max_wf_y_pixel_coord)
01011               tmp_wf_y_pixel_coord = max_wf_y_pixel_coord;
01012             
01013             index = (int)((ceil(tmp_wf_y_pixel_coord)-1
01014                         +layer_y_extrapix+this->axes[1]/2)*this->axes[0] +
01015                         ceil(tmp_wf_x_pixel_coord)-1
01016                         +layer_x_extrapix+this->axes[0]/2);
01017             
01018             if(index<0 || index>=layer_nelem){
01019               cerr << "\nrefractive_atmospheric_layer::aligned_private_transform"
01020                    << "- impending doom\n";
01021               cerr << i << "\t" << j << "\t" << index << "\t" << layer_nelem
01022                    << endl;
01023               cerr << wf_x_pixel_coord << "\t" << tmp_wf_x_pixel_coord 
01024                    << "\t" << ceil(tmp_wf_x_pixel_coord) << "\t" 
01025                    << max_wf_x_pixel_coord << endl;
01026               cerr << wf_y_pixel_coord << "\t" << tmp_wf_y_pixel_coord 
01027                    << "\t" << ceil(tmp_wf_y_pixel_coord) << "\t" 
01028                    << max_wf_y_pixel_coord << endl;
01029               cerr << this->axes[0] << "\t" << this->axes[1] << endl;
01030               cerr << wf_axes[0] << "\t" << wf_axes[1] << endl;
01031               throw(string("xxx"));
01032             }
01033 
01034             refractive_optical_path += 
01035               this->pixeldata[index]*
01036               (tmp_wf_x_pixel_coord - wf_x_pixel_coord)
01037               *(tmp_wf_y_pixel_coord - wf_y_pixel_coord);
01038 
01039             area += (tmp_wf_x_pixel_coord - wf_x_pixel_coord)
01040                 *(tmp_wf_y_pixel_coord - wf_y_pixel_coord);
01041 
01042             wf_y_pixel_coord = tmp_wf_y_pixel_coord;
01043             tmp_wf_y_pixel_coord++;
01044           }
01045           wf_x_pixel_coord = tmp_wf_x_pixel_coord;
01046           tmp_wf_x_pixel_coord++;
01047         }
01048 
01049         // add in the phase 
01050         tmp = refractive_optical_path*2*M_PI/wf_wavelength/area;
01051         if(is_interleaved){
01052           index = (i+wf_axes[1]/2)*wf_axes[0] + j + wf_axes[0]/2;
01053           wfdata[2*index+1] += tmp;
01054         } else if(!is_interleaved){
01055           index = (i+wf_axes[1]/2)*wf_axes[0] + j + wf_axes[0]/2;
01056           wfdata[index+wf_nelem] += tmp;
01057         }       
01058       }
01059     }
01060   }
01061   */
01062 
01063   template<class T> template<class U>
01064   void refractive_atmospheric_layer<T>::
01065     aligned_private_transform(diffractive_wavefront<U> & wf) const {
01066 
01067     // First, ensure that the center of this wavefront lies in the
01068     // plane of the layer
01069     if(operator!=(static_cast<three_point>(wf),
01070                   static_cast<three_point>(*this))){
01071       three_vector origin_offset = 
01072         static_cast<three_point>(wf) - static_cast<three_point>(*this);
01073     
01074       if(fabs(dot_product(origin_offset,
01075                           this->three_frame::z()))>three_frame::precision){
01076         cerr << "refractive_atmospheric_layer::aligned_private_transform error - "
01077              << "diffractive_wavefront center not in transverse plane of layer\n";
01078         wf.three_point::print(cerr, *this, "wavefront center in frame of layer ");
01079         throw(string("refractive_atmospheric_layer::aligned_private_transform"));
01080       }
01081     }
01082     
01083     // Verify that the transverse axes are aligned. 
01084     // This check is valid regardless of the foreshortening
01085     // status.
01086     if(fabs(dot_product(wf.x(), this->y()))>three_frame::precision &&
01087        fabs(dot_product(wf.y(), this->x()))<three_frame::precision){
01088       cerr << "refractive_atmospheric_layer::aligned_private_transform error - "
01089            << "the wavefront transverse axes are not aligned "
01090            << "with those of the layer\n";
01091       throw(string("refractive_atmospheric_layer::aligned_private_transform"));
01092     }
01093 
01094     three_frame wind_blown_frame(*this);
01095     wind_blown_frame += wf.get_timestamp()*this->get_wind_vector();
01096 
01097     //(wf.get_timestamp()*this->get_wind_vector()).print(cerr, "wind vector ");
01098 
01099     // Verify that the wavefront is fully contained by the layer.
01100     rectangular_region layer_region, wf_region, modified_wf_region;
01101 
01102     try{
01103       layer_region = rectangular_region(wind_blown_frame,
01104                                         this->get_axes(), 
01105                                         this->get_pixel_scale());
01106     } catch(...) {
01107       cerr << "refractive_atmospheric_layer::aligned_private_transform error - "
01108            << "could not get layer region\n";
01109       throw(string("refractive_atmospheric_layer::aligned_private_transform"));
01110     }
01111 
01112     try{
01113       wf_region = rectangular_region(wf, 
01114                                      wf.get_axes(), 
01115                                      wf.get_pixel_scale());
01116     } catch(...) {
01117       cerr << "refractive_atmospheric_layer::aligned_private_transform error - "
01118            << "could not get layer region\n";
01119       throw(string("refractive_atmospheric_layer::aligned_private_transform"));
01120     }
01121 
01122     if(this->foreshortening){
01123       modified_wf_region = rectangular_region(wf_region, 
01124                                               this->z(), 
01125                                               false);
01126     } else {
01127       three_frame tmp_frame;
01128       if(dot_product(wf.z(), this->z())>0)
01129         tmp_frame = three_frame(wf, this->x(), this->y(), this->z());
01130       else 
01131         tmp_frame = three_frame(wf, this->x(), this->y(), -1*this->z());
01132       modified_wf_region = rectangular_region(tmp_frame,
01133                                               wf.get_axes(), 
01134                                               wf.get_pixel_scale());
01135     }
01136 
01137     if(!layer_region.contains(modified_wf_region)){
01138       cerr << "refractive_atmospheric_layer::aligned_private_transform error - "
01139            << "layer does not contain wavefront\n";
01140       layer_region.print(cerr, "layer region ");
01141       modified_wf_region.print(cerr, "wfrnt region ");
01142       throw(string("refractive_atmospheric_layer::aligned_private_transform"));
01143     }
01144 
01145     // the half pixel definitions - so that
01146     // when you have even axes the pixel
01147     // centroids lie on half pixel values.
01148     vector<long> wf_axes = wf.get_axes();
01149     double wf_x_halfpix=0, wf_y_halfpix=0;
01150     double layer_x_halfpix=0, layer_y_halfpix=0;
01151     int wf_x_extrapix=1, wf_y_extrapix=1;
01152     int layer_x_extrapix=1, layer_y_extrapix=1;
01153     if(wf_axes[1]%2==0){
01154       wf_x_halfpix = .5;
01155       wf_x_extrapix = 0;
01156     }
01157     if(wf_axes[0]%2==0){
01158       wf_y_halfpix = .5;
01159       wf_y_extrapix = 0;
01160     }
01161     if(this->axes[1]%2==0){
01162       layer_x_halfpix = .5;
01163       layer_x_extrapix = 0;
01164     }
01165     if(this->axes[0]%2==0){
01166       layer_y_halfpix = .5;
01167       layer_y_extrapix = 0;
01168     }
01169 
01170     double x_sign = 1;
01171     if(dot_product(wf.x(),this->x())<0)
01172       x_sign = -1;
01173     double y_sign = 1;
01174     if(dot_product(wf.y(),this->y())<0)
01175       y_sign = -1;
01176 
01177     //cerr << "x sign " << x_sign << " y sign " << y_sign << endl;
01178 
01179     // Finally, we are ready to run through the arrays adding the layer
01180     // to the wavefront.  If foreshortening is on the pixel scale of the
01181     // wavefront may differ in the x and y direction, due to the
01182     // projection effect.  Here we define some quantities to specify the
01183     // wf pixel scales
01184     double wf_x_pixscale = wf.get_pixel_scale();
01185     double wf_y_pixscale = wf.get_pixel_scale();
01186     double dp;
01187     if(this->get_foreshortening()){
01188       dp = dot_product(wf.x(), this->x());
01189       wf_x_pixscale /= (dp*dp);
01190       dp = dot_product(wf.y(), this->y());
01191       wf_y_pixscale /= (dp*dp);
01192       if(optic::verbose_level)
01193         cout << "refractive_atmospheric_layer::aligned_private_transform -\n"
01194              << "\twavefront pixel scale " << wf.get_pixel_scale() << endl
01195              << "\tprojected x pixel scale " << wf_x_pixscale << endl
01196              << "\tprojected y pixel scale " << wf_y_pixscale << endl;
01197     }
01198 
01199     // Convert the wavefront to amplitude and phase.  In this way
01200     // we can add in the phase from the layer OPD and it won't wrap
01201     this->wavefront_amp_phase_conversion(wf);
01202     U * wfdata = this->get_wavefront_data(wf);
01203 
01204     // Next, for each pixel in the wavefront, we are going to average
01205     // over the pixels in the layer that are contained by the wavefront
01206     // pixel.  If there are layer pixels that partially overlap the
01207     // wavefront pixel, we'll downweight them by their areal overlap.
01208 
01209     double wf_wavelength = wf.get_wavelength();
01210     double lower_wf_x_pixel_coord, lower_wf_y_pixel_coord;
01211     double upper_wf_x_pixel_coord, upper_wf_y_pixel_coord;
01212     long index_wf_x_pixel_coord, index_wf_y_pixel_coord;
01213 
01214     double min_wf_x_pixel_coord, min_wf_y_pixel_coord;
01215     double max_wf_x_pixel_coord, max_wf_y_pixel_coord;
01216 
01217     double area, refractive_optical_path;
01218 
01219     three_vector origin_offset = wf - wind_blown_frame;
01220     bool is_real_imag = this->is_real_imag_storage(wf);
01221     bool is_interleaved = this->is_interleaved_storage(wf);
01222     double tmp;
01223     int index, wf_nelem = wf_axes[0]*wf_axes[1],
01224       layer_nelem = this->axes[0]*this->axes[1];
01225 
01226     /*
01227     origin_offset.print(cerr, "origin offset ");
01228     cerr << "x offset "
01229          << origin_offset.x(wind_blown_frame)
01230          << endl;
01231     cerr << "y offset "
01232          << origin_offset.y(wind_blown_frame)
01233          << endl;
01234     cerr << endl << endl;
01235     */
01236 
01237     for(int i=-wf_axes[1]/2; i<wf_axes[1]/2+wf_x_extrapix; i++){
01238       for(int j=-wf_axes[0]/2; j<wf_axes[0]/2+wf_y_extrapix; j++){
01239       
01240         // These are the coordinates of the lower corner of the wf pixel
01241         // in the wind blown frame, measured in units of the layer pixel scale.
01242         /*
01243         min_wf_x_pixel_coord = ((j+wf_x_halfpix-.5)*wf_x_pixscale + 
01244                                 origin_offset.x(wind_blown_frame))/this->pixel_scale;
01245         min_wf_y_pixel_coord = ((i+wf_y_halfpix-.5)*wf_y_pixscale + 
01246                                 origin_offset.y(wind_blown_frame))/this->pixel_scale;
01247         */
01248         min_wf_x_pixel_coord = (((j+wf_x_halfpix)*x_sign - .5)*wf_x_pixscale + 
01249                                 origin_offset.x(wind_blown_frame))/this->pixel_scale;
01250         min_wf_y_pixel_coord = (((i+wf_y_halfpix)*y_sign - .5)*wf_y_pixscale + 
01251                                 origin_offset.y(wind_blown_frame))/this->pixel_scale;
01252         /*
01253         if(i==0 && j==0){
01254           cerr << "xxx - min wf x coord " << min_wf_x_pixel_coord << endl;
01255           cerr << "xxx - min wf y coord " << min_wf_y_pixel_coord << endl;
01256         }
01257         */
01258 
01259         // These are the coordinates of the upper corner of the wf pixel
01260         // in the wind blown frame, measured in units of the layer pixel scale.
01261         max_wf_x_pixel_coord = min_wf_x_pixel_coord + wf_x_pixscale/this->pixel_scale;
01262         max_wf_y_pixel_coord = min_wf_y_pixel_coord + wf_y_pixscale/this->pixel_scale;
01263 
01264         /*
01265         if(i==0 && j==0){
01266           cerr << "xxx - max wf x coord " << max_wf_x_pixel_coord << endl;
01267           cerr << "xxx - max wf y coord " << max_wf_y_pixel_coord << endl;
01268         }
01269         */
01270 
01271         refractive_optical_path = 0;
01272 
01273         index_wf_x_pixel_coord = (long)floor(min_wf_x_pixel_coord);
01274         while(index_wf_x_pixel_coord < max_wf_x_pixel_coord){
01275           index_wf_y_pixel_coord = (long)floor(min_wf_y_pixel_coord);
01276           while(index_wf_y_pixel_coord < max_wf_y_pixel_coord){
01277 
01278             // This is the index into the layer array
01279             index = 
01280               (index_wf_y_pixel_coord+layer_y_extrapix+this->axes[1]/2)*this->axes[0] +
01281               index_wf_x_pixel_coord+layer_x_extrapix+this->axes[0]/2;
01282             
01283             lower_wf_x_pixel_coord = 
01284               index_wf_x_pixel_coord < min_wf_x_pixel_coord ? 
01285               min_wf_x_pixel_coord : index_wf_x_pixel_coord;
01286 
01287             lower_wf_y_pixel_coord = 
01288               index_wf_y_pixel_coord < min_wf_y_pixel_coord ? 
01289               min_wf_y_pixel_coord : index_wf_y_pixel_coord;
01290 
01291             upper_wf_x_pixel_coord = 
01292               index_wf_x_pixel_coord + 1 < max_wf_x_pixel_coord ? 
01293               index_wf_x_pixel_coord + 1 : max_wf_x_pixel_coord;
01294 
01295             upper_wf_y_pixel_coord = 
01296               index_wf_y_pixel_coord + 1 < max_wf_y_pixel_coord ? 
01297               index_wf_y_pixel_coord + 1 : max_wf_y_pixel_coord;
01298 
01299             /*
01300             if(i==0 && j==0){
01301               cerr << "xxx - lower wf coords " 
01302                    << lower_wf_x_pixel_coord 
01303                    << ","
01304                    << lower_wf_y_pixel_coord 
01305                    << endl;
01306               cerr << "xxx - index wf coords " 
01307                    << index_wf_x_pixel_coord 
01308                    << ","
01309                    << index_wf_y_pixel_coord 
01310                    << endl;
01311               cerr << "xxx - upper wf coords " 
01312                    << upper_wf_x_pixel_coord 
01313                    << ","
01314                    << upper_wf_y_pixel_coord 
01315                    << endl;
01316             }
01317             */
01318         
01319             area = (upper_wf_x_pixel_coord - lower_wf_x_pixel_coord)
01320               *(upper_wf_y_pixel_coord - lower_wf_y_pixel_coord);
01321 
01322             /*
01323             if(i==0 && j==0){
01324               cerr << "xxx - area " << area << endl;
01325             }
01326             */
01327 
01328             if(index<0 || index>=layer_nelem || area<=0){
01329               cerr << "\nrefractive_atmospheric_layer::aligned_private_transform"
01330                    << " - error transforming wavefront\n";
01331               cerr << "indices "
01332                    << i 
01333                    << "\t" << j 
01334                    << "\t" << index 
01335                    << "\t" << layer_nelem
01336                    << endl;
01337               cerr << "x coords "
01338                    << "\tlower " << lower_wf_x_pixel_coord 
01339                    << "\tupper " << upper_wf_x_pixel_coord 
01340                    << "\tmin   " << min_wf_x_pixel_coord 
01341                    << "\tmax   " << max_wf_x_pixel_coord 
01342                    << endl;
01343               cerr << "y coords "
01344                    << "\tlower " << lower_wf_y_pixel_coord 
01345                    << "\tupper " << upper_wf_y_pixel_coord 
01346                    << "\tmin   " << min_wf_y_pixel_coord 
01347                    << "\tmax   " << max_wf_y_pixel_coord 
01348                    << endl;
01349               cerr << "layer axes "
01350                    << this->axes[0] 
01351                    << "\t" << this->axes[1] 
01352                    << endl;
01353               cerr << "wavefront axes "
01354                    << wf_axes[0] 
01355                    << "\t" << wf_axes[1] 
01356                    << endl;
01357               cerr << "area "
01358                    << area
01359                    << endl;
01360               throw(string("refractive_atmospheric_layer::aligned_private_transform"));
01361             }
01362 
01363             refractive_optical_path += 
01364               this->pixeldata[index]*area;
01365 
01366             /*
01367             if(i==0 && j==0){
01368               cerr << "xxx - refractive optical path " 
01369                    << this->pixeldata[index] 
01370                    << "\t"
01371                    << this->pixeldata[index]*area
01372                    << "\t"
01373                    << refractive_optical_path 
01374                    << endl;
01375             }
01376             */
01377 
01378             index_wf_y_pixel_coord++;
01379           }
01380           index_wf_x_pixel_coord++;
01381         }
01382 
01383         // add in the phase 
01384         tmp = refractive_optical_path*2*M_PI/wf_wavelength;
01385 
01386         /*
01387         if(i==0 && j==0){
01388           cerr << "xxx - layer x index " << index_wf_y_pixel_coord+layer_y_extrapix+this->axes[1]/2 << endl;
01389           cerr << "xxx - layer y index " << index_wf_x_pixel_coord+layer_x_extrapix+this->axes[0]/2 << endl;
01390           cerr << "xxx - refractive optical path " << refractive_optical_path << endl;
01391           cerr << "xxx - phase difference " << tmp << endl << endl;
01392         }
01393         */
01394 
01395         if(is_interleaved){
01396           index = (i+wf_axes[1]/2)*wf_axes[0] + j + wf_axes[0]/2;
01397           wfdata[2*index+1] += tmp;
01398         } else if(!is_interleaved){
01399           index = (i+wf_axes[1]/2)*wf_axes[0] + j + wf_axes[0]/2;
01400           wfdata[index+wf_nelem] += tmp;
01401         }       
01402       }
01403     }
01404   }
01405 }
01406 
01407 #endif

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