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

observation.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 OBSERVATION_H
00032 #define OBSERVATION_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 "diffractive_wavefront.h"
00041 
00042 namespace Arroyo {
00043 
00044 
00045   template <typename precision> class basic_otf;
00046 
00050 
00051   class observation_base {
00052 
00053     public:
00054 
00057     observation_base(){};
00058 
00061     virtual ~observation_base(){};
00062 
00065     virtual void read(const char* filename) = 0;
00066 
00069     virtual void read(const iofits& iof) = 0;
00070 
00073     virtual void write(const char* filename) const = 0;
00074 
00077     virtual void write(iofits & iof) const = 0;
00078 
00081     virtual void print(ostream & os, const char* prefix="") const = 0;
00082 
00085     static observation_base* observation_base_factory(const char* filename);
00086 
00089     static observation_base* observation_base_factory(const iofits& iof);
00090   };
00091 
00092 
00093   template<class precision>
00094     class basic_observation :
00095     public AO_sim_base,
00096     public observation_base, 
00097     public Arroyo::pixel_amp_array<precision> {
00098 
00099     private:
00100 
00101     static const bool factory_registration;
00102 
00105     string unique_name() const {return(string("basic observation"));};
00106 
00107     protected:
00108 
00109     double right_ascension_radians;
00110     
00111     double declination_radians;
00112     
00113     double pixel_scale_radians_per_pixel;
00114     
00115     double wavelength_meters;
00116 
00117     public:
00118 
00121     basic_observation();
00122 
00125     ~basic_observation(){};
00126 
00129     basic_observation(const basic_observation & basic_obs){
00130       this->operator=(basic_obs);
00131     };
00132 
00135     basic_observation(const char * filename){
00136       this->read(filename);
00137     };
00138 
00141     basic_observation(const iofits & iof){
00142       this->read(iof);
00143     };
00144 
00147     basic_observation(double ra_radians,
00148                       double dec_radians,
00149                       double pixel_scale_radians_per_pixel,
00150                       double wavelength_meters,
00151                       const pixel_amp_array<precision> & pixamparr);
00152 
00153 
00156     basic_observation(double aperture_diameter_meters, 
00157                       double focal_plane_image_size_arcsecs,
00158                       double oversampling_factor,
00159                       const basic_otf<precision> & otf);
00160 
00161     /*
00164     basic_observation(int psf_dimen,
00165                       double wavelength_meters,
00166                       double pixel_scale_radians_per_pixel,
00167                       double aperture_diameter_meters,
00168                       pixel_amp_array<precision> OTF_amps,
00169                       pixel_phase_array<precision> OTF_phases);
00170     */
00171 
00174     basic_observation & operator=(const basic_observation & basic_obs);
00175 
00178     void read(const char * filename);
00179 
00182     void read(const Arroyo::iofits & iof);
00183 
00186     void write(const char * filename) const;
00187 
00190     void write(Arroyo::iofits & iof) const;
00191 
00194     void print(std::ostream & os, const char * prefix = "") const;
00195 
00198     double get_ra() const {return(right_ascension_radians);};
00199    
00202     double get_dec() const {return(declination_radians);};
00203    
00206     double get_pixel_scale() const {return(pixel_scale_radians_per_pixel);};
00207    
00210     double get_wavelength() const {return(wavelength_meters);};
00211    
00219     vector<pair<double, double> > ensquared_energy() const;
00220 
00221 
00222     /*
00225     void optical_transfer_function(int otf_dimen,
00226                                    double aperture_diameter_meters,
00227                                    pixel_amp_array<precision> & OTF_amps,
00228                                    pixel_phase_array<precision> & OTF_phases) const;
00229     */
00230   };
00231 
00232   template <class precision> 
00233     basic_otf<precision> operator * (const basic_otf<precision> & p1,
00234                                      double & fac);
00235   
00236   template <class precision> 
00237     basic_otf<precision> operator * (const basic_otf<precision> & p1,
00238                                      const basic_otf<precision> & p2);
00239   
00240   template <class precision> 
00241     basic_otf<precision> operator / (const basic_otf<precision> & p1,
00242                                      const basic_otf<precision> & p2);
00243   
00244   template <class precision> 
00245     basic_otf<precision> operator + (const basic_otf<precision> & p1,
00246                                      const basic_otf<precision> & p2);
00247   
00248 
00249   template<class precision>
00250     class basic_otf :
00251     public AO_sim_base {
00252 
00253     private:
00254 
00255     static const bool factory_registration;
00256 
00259     string unique_name() const {return(string("optical transfer function"));};
00260 
00261     protected:
00262 
00263     double right_ascension_radians;
00264     
00265     double declination_radians;
00266     
00267     double pupil_plane_pixel_scale_meters;
00268     
00269     double wavelength_meters;
00270 
00271     pixel_amp_array<precision> OTF_amps;
00272     pixel_phase_array<precision> OTF_phases;
00273 
00274     public:
00275 
00278     basic_otf();
00279 
00282     ~basic_otf(){};
00283 
00286     basic_otf(const basic_otf & otf){
00287       this->operator=(otf);
00288     };
00289 
00292     basic_otf(const char * filename){
00293       this->read(filename);
00294     };
00295 
00298     basic_otf(const iofits & iof){
00299       this->read(iof);
00300     };
00301 
00304     basic_otf(double ra_radians,
00305               double dec_radians,
00306               double pupil_plane_pixel_scale_meters,
00307               double wavelength_meters,
00308               const pixel_amp_array<precision> & otf_amps,
00309               const pixel_phase_array<precision> & otf_phases);
00310     
00313     basic_otf(double aperture_diameter_meters, 
00314               double pupil_plane_pixel_scale_meters, 
00315               const basic_observation<precision> & basic_obs);
00316 
00319     basic_otf & operator=(const basic_otf & otf);
00320 
00323     void read(const char * filename);
00324 
00327     void read(const Arroyo::iofits & iof);
00328 
00331     void write(const char * filename) const;
00332 
00335     void write(Arroyo::iofits & iof) const;
00336 
00339     void print(std::ostream & os, const char * prefix = "") const;
00340 
00343     double get_ra() const {return(right_ascension_radians);};
00344    
00347     double get_dec() const {return(declination_radians);};
00348    
00351     double get_pixel_scale() const {return(pupil_plane_pixel_scale_meters);};
00352    
00355     double get_wavelength() const {return(wavelength_meters);};
00356    
00359     vector<long> get_axes() const {return(this->OTF_amps.get_axes());};
00360    
00363     complex<precision> data(int index) const {
00364       return(polar(this->OTF_amps.data(index), 
00365                    this->OTF_phases.data(index)));
00366     };
00367 
00370     pixel_amp_array<precision> get_amps() const {
00371       return(OTF_amps);
00372     };
00373 
00376     pixel_phase_array<precision> get_phases() const {
00377       return(OTF_phases);
00378     };
00379 
00382     void set_data(int index, complex<precision> cmplx) const {
00383       this->OTF_amps.set_data(index, abs(cmplx)); 
00384       this->OTF_phases.set_data(index, arg(cmplx)); 
00385     };
00386 
00389     void pad(int padlength) {
00390       this->OTF_amps.pad_array(padlength);
00391       this->OTF_phases.pad_array(padlength);
00392     }
00393 
00396     void clip(int cliplength) {
00397       this->OTF_amps.clip_array(cliplength);
00398       this->OTF_phases.clip_array(cliplength);
00399     }
00400 
00403     basic_otf<precision> & operator*=(const basic_otf<precision> & rhs);
00404 
00407     basic_otf<precision> & operator/=(const basic_otf<precision> & rhs);
00408 
00411     basic_otf<precision> & operator*=(double fac);
00412 
00415     basic_otf<precision> & operator+=(const basic_otf<precision> & rhs);
00416 
00419     basic_otf<precision> & operator-=(const basic_otf<precision> & rhs);
00420 
00421   };
00422 
00423   template<class precision>
00424     basic_observation<precision>::
00425     basic_observation(){
00426     
00427     this->right_ascension_radians = 0;
00428     this->declination_radians = 0;
00429     this->pixel_scale_radians_per_pixel = -1;
00430     this->wavelength_meters = -1;
00431 
00432   }
00433 
00434   template<class precision>
00435     basic_observation<precision>::
00436     basic_observation(double ra_radians,
00437                       double dec_radians,
00438                       double pixscale_radians_per_pixel,
00439                       double wavelength_meters,
00440                       const pixel_amp_array<precision> & pixamparr){
00441 
00442     this->right_ascension_radians = ra_radians;
00443     this->declination_radians = dec_radians;
00444     this->pixel_scale_radians_per_pixel = pixscale_radians_per_pixel;
00445     this->wavelength_meters = wavelength_meters;
00446 
00447     this->pixel_amp_array<precision>::operator=(pixamparr);
00448 
00449   }
00450 
00451   /*
00452   template<typename precision>
00453     basic_observation<precision>::basic_observation(int psf_dimen,
00454                                                     double wavelength_meters,
00455                                                     double pixel_scale_radians_per_pixel,
00456                                                     double aperture_diameter_meters,
00457                                                     pixel_amp_array<precision> OTF_amps,
00458                                                     pixel_phase_array<precision> OTF_phases) {
00459 
00460 
00461     try{
00462       
00463       if(OTF_amps.get_axes()!=OTF_phases.get_axes()){
00464         cerr << "basic_observation::basic_observation error - axes mismatch\n";
00465         throw(string("basic_observation::basic_observation"));
00466       }
00467 
00468       if(aperture_diameter_meters<=0){
00469         cerr << "basic_observation::basic_observation error - aperture diameter "
00470              << aperture_diameter_meters
00471              << " out of range\n";
00472         throw(string("basic_observation::basic_observation"));
00473       }
00474 
00475       this->wavelength_meters = wavelength_meters;
00476       this->pixel_scale_radians_per_pixel = pixel_scale_radians_per_pixel;
00477       this->set_axes(vector<long>(2,psf_dimen));
00478       
00479       // set up the storage
00480       vector<long> otf_axes = OTF_amps.get_axes();
00481       vector<long> psf_axes(2, psf_dimen);
00482       
00483       int notf_elems = OTF_amps.total_space();
00484       int npsf_elems = this->axes[0]*this->axes[1];
00485       precision *otf_data;
00486       precision *psf_data;    
00487       try{
00488         otf_data = new precision[2*notf_elems];
00489         psf_data = new precision[2*npsf_elems];
00490       } catch(...) {
00491         cerr << "basic_observation::basic_observation - error allocating memory\n";
00492         throw(string("basic_observation::basic_observation"));
00493       }
00494       
00495       // Slope correction for even dimension arrays
00496       double xslope = this->axes[1]%2==1 ? 0 : M_PI/(double)(psf_axes[1]/2);
00497       double yslope = this->axes[0]%2==1 ? 0 : M_PI/(double)(psf_axes[0]/2);
00498 
00499       // Halfpixel information
00500       double otf_x_halfpix=0, otf_y_halfpix=0;
00501       int otf_x_extrapix=1, otf_y_extrapix=1;
00502       if(otf_axes[1]%2==0){
00503         otf_x_halfpix = .5;
00504         otf_x_extrapix = 0;
00505       }
00506       if(otf_axes[0]%2==0){
00507         otf_y_halfpix = .5;
00508         otf_y_extrapix = 0;
00509       }
00510       double psf_x_halfpix=0, psf_y_halfpix=0;
00511       int psf_x_extrapix=1, psf_y_extrapix=1;
00512       if(this->axes[1]%2==0){
00513         psf_x_halfpix = .5;
00514         psf_x_extrapix = 0;
00515       }
00516       if(this->axes[0]%2==0){
00517         psf_y_halfpix = .5;
00518         psf_y_extrapix = 0;
00519       }
00520 
00521       // Initialize the complex PSF data array
00522       int index;
00523       double twopi = 2*M_PI;
00524       double amp, phase;
00525       for(int i=-otf_axes[1]/2; i<otf_axes[1]/2+otf_x_extrapix; i++){
00526         for(int j=-otf_axes[0]/2; j<otf_axes[0]/2+otf_y_extrapix; j++){
00527           index = (i+otf_axes[1]/2)*otf_axes[0]+j+otf_axes[0]/2;
00528           amp = OTF_amps.data(index);
00529           phase = OTF_phases.data(index) + fmod(-xslope*(i+otf_x_halfpix) - yslope*(j+otf_y_halfpix), twopi);
00530           otf_data[2*index] = amp*cos(phase);
00531           otf_data[2*index+1] = amp*sin(phase);
00532         }
00533       }
00534 
00535       double oversampling_factor = 
00536         wavelength_meters / pixel_scale_radians_per_pixel / aperture_diameter_meters;
00537 
00538       //cerr << "oversampling factor " << oversampling_factor << endl;
00539 
00540       double extra_fac = 2*(double)this->axes[0]/(double)otf_axes[0];
00541 
00542       //double sampling_factor = -2/(double)otf_axes[0]/oversampling_factor;
00543       double sampling_factor = -extra_fac/(double)this->axes[0]/oversampling_factor;
00544 
00545       //double normalization_factor = fabs(sampling_factor);
00546 
00547       goertzel_reinsch_transform(otf_axes, this->axes, sampling_factor, otf_data, psf_data);
00548 
00549       delete [] otf_data;
00550 
00551       // No need to fix up the slopes here - we just want the amplitude
00552       for(int i=0; i<npsf_elems; i++)
00553         this->pixeldata[i] = 
00554           sqrt(psf_data[2*i]*psf_data[2*i] + psf_data[2*i+1]*psf_data[2*i+1]);
00555 
00556       delete [] psf_data;
00557 
00558       } catch(...) {
00559       cerr << "basic_observation::basic_observation error\n";
00560       throw(string("basic_observation::basic_observation"));
00561     }
00562   }
00563   */
00564 
00565 
00566   template<typename precision>
00567     basic_observation<precision>::basic_observation(double aperture_diameter_meters,
00568                                                     double focal_plane_image_size_arcsecs,
00569                                                     double oversampling_factor,
00570                                                     const basic_otf<precision> & otf) {
00571 
00572 
00573     try{
00574       
00575       if(aperture_diameter_meters<=0){
00576         cerr << "basic_observation::basic_observation error - aperture diameter "
00577              << aperture_diameter_meters
00578              << " out of range\n";
00579         throw(string("basic_observation::basic_observation"));
00580       }
00581 
00582       if(focal_plane_image_size_arcsecs<=0){
00583         cerr << "basic_observation::basic_observation error - focal plane image size "
00584              << focal_plane_image_size_arcsecs
00585              << " out of range\n";
00586         throw(string("basic_observation::basic_observation"));
00587       }
00588 
00589       if(oversampling_factor<=0){
00590         cerr << "basic_observation::basic_observation error - oversampling factor "
00591              << oversampling_factor
00592              << " out of range\n";
00593         throw(string("basic_observation::basic_observation"));
00594       }
00595 
00596       double arcsecs_to_radians = M_PI/180./3600.;
00597 
00598       vector<long> otf_axes = otf.get_axes();
00599       double nyquist_pixel_scale_radians_per_pixel = 
00600         otf.get_wavelength() / 2. / aperture_diameter_meters;
00601       this->wavelength_meters = otf.get_wavelength();
00602       this->pixel_scale_radians_per_pixel = nyquist_pixel_scale_radians_per_pixel/oversampling_factor;
00603       long psf_dimen = (long)(ceil(focal_plane_image_size_arcsecs*arcsecs_to_radians/this->pixel_scale_radians_per_pixel));
00604       vector<long> psf_axes(2,psf_dimen);
00605       this->set_axes(psf_axes);
00606       
00607       // set up the storage      
00608       int notf_elems = otf_axes[0]*otf_axes[1];
00609       int npsf_elems = psf_axes[0]*psf_axes[1];
00610       precision *otf_data;
00611       precision *psf_data;    
00612       try{
00613         otf_data = new precision[2*notf_elems];
00614         psf_data = new precision[2*npsf_elems];
00615       } catch(...) {
00616         cerr << "basic_observation::basic_observation - error allocating memory\n";
00617         throw(string("basic_observation::basic_observation"));
00618       }
00619       
00620       // Slope correction for even dimension arrays
00621       double fac = 2*this->pixel_scale_radians_per_pixel/nyquist_pixel_scale_radians_per_pixel;
00622       double xslope = psf_axes[1]%2==1 ? 0 : M_PI*fac/(double)(otf_axes[1]);
00623       double yslope = psf_axes[0]%2==1 ? 0 : M_PI*fac/(double)(otf_axes[0]);
00624 
00625       // Halfpixel information
00626       double otf_x_halfpix=0, otf_y_halfpix=0;
00627       int otf_x_extrapix=1, otf_y_extrapix=1;
00628       if(otf_axes[1]%2==0){
00629         otf_x_halfpix = .5;
00630         otf_x_extrapix = 0;
00631       }
00632       if(otf_axes[0]%2==0){
00633         otf_y_halfpix = .5;
00634         otf_y_extrapix = 0;
00635       }
00636       double psf_x_halfpix=0, psf_y_halfpix=0;
00637       int psf_x_extrapix=1, psf_y_extrapix=1;
00638       if(this->axes[1]%2==0){
00639         psf_x_halfpix = .5;
00640         psf_x_extrapix = 0;
00641       }
00642       if(this->axes[0]%2==0){
00643         psf_y_halfpix = .5;
00644         psf_y_extrapix = 0;
00645       }
00646 
00647       // Initialize the complex PSF data array
00648       int index;
00649       double twopi = 2*M_PI;
00650       double amp, phase;
00651       complex<precision> cmp;
00652       for(int i=-otf_axes[1]/2; i<otf_axes[1]/2+otf_x_extrapix; i++){
00653         for(int j=-otf_axes[0]/2; j<otf_axes[0]/2+otf_y_extrapix; j++){
00654           index = (i+otf_axes[1]/2)*otf_axes[0]+j+otf_axes[0]/2;
00655           cmp = otf.data(index);
00656           amp = abs(cmp);
00657           phase = fmod(arg(cmp) - xslope*(i+otf_x_halfpix) - yslope*(j+otf_y_halfpix), twopi);
00658           otf_data[2*index] = amp*cos(phase);
00659           otf_data[2*index+1] = amp*sin(phase);
00660         }
00661       }
00662 
00663       //double sampling_factor = -2/(double)otf_axes[0]/oversampling_factor;
00664       double sampling_factor = -1/(double)otf_axes[0]/oversampling_factor;
00665 
00666       goertzel_reinsch_transform(otf_axes, psf_axes, sampling_factor, otf_data, psf_data);
00667 
00668       delete [] otf_data;
00669 
00670       // No need to fix up the slopes here - we just want the amplitude
00671       for(int i=0; i<npsf_elems; i++)
00672         this->pixeldata[i] = 
00673           sqrt(psf_data[2*i]*psf_data[2*i] + psf_data[2*i+1]*psf_data[2*i+1]);
00674 
00675       delete [] psf_data;
00676 
00677       } catch(...) {
00678       cerr << "basic_observation::basic_observation error\n";
00679       throw(string("basic_observation::basic_observation"));
00680     }
00681   }
00682 
00683 
00684   template<class precision>
00685   basic_observation<precision> & basic_observation<precision>::
00686   operator=(const basic_observation<precision> & basic_obs){
00687     if(this==&basic_obs)
00688       return(*this);
00689 
00690     this->right_ascension_radians = basic_obs.right_ascension_radians;
00691     this->declination_radians = basic_obs.declination_radians;
00692     this->pixel_scale_radians_per_pixel = basic_obs.pixel_scale_radians_per_pixel;
00693     this->wavelength_meters = basic_obs.wavelength_meters;
00694 
00695     this->pixel_amp_array<precision>::operator=(basic_obs);
00696 
00697     return(*this);
00698   }
00699 
00700   template<class precision>
00701   void basic_observation<precision>::read(const char * filename){
00702     iofits iof;
00703     try{iof.open(filename);}
00704     catch(...){
00705       cerr << "basic_observation::read - "
00706            << "error opening file " << filename << endl;
00707       throw(string("basic_observation::read"));
00708     }
00709     try{this->read(iof);}
00710     catch(...){
00711       cerr << "basic_observation::read - "
00712            << "error reading "
00713            << this->unique_name() << " from file "
00714            << filename << endl;
00715       throw(string("basic_observation::read"));
00716     }
00717   }
00718 
00719   template<class precision>
00720   void basic_observation<precision>::read(const iofits & iof){
00721 
00722     if(!iof.key_exists("TYPE")){
00723       cerr << "basic_observation::read error - "
00724            << "unrecognized type of file\n";
00725       iof.print_header(cerr, "hdr dump");
00726       cerr << "hdu num " << iof.get_hdu_num() << " of "
00727            << iof.get_num_hdus() << endl;
00728       throw(string("basic_observation::read"));
00729     }
00730 
00731     string type, comment;
00732     iof.read_key("TYPE", type, comment);
00733     if(type!=this->unique_name()){
00734       cerr << "basic_observation::read error - file of type " 
00735            << type << " rather than of type "
00736            << this->unique_name() << endl;
00737       throw(string("basic_observation::read"));
00738     }
00739 
00740     iof.read_key("CDELT1", this->pixel_scale_radians_per_pixel, comment);
00741     iof.read_key("CRVAL1", this->right_ascension_radians, comment);
00742     iof.read_key("CRVAL2", this->declination_radians, comment);
00743 
00744     double radians_to_degrees = 180./M_PI;
00745     double degrees_to_radians = M_PI/180.;
00746 
00747 
00748     this->pixel_scale_radians_per_pixel *= -1*degrees_to_radians;
00749     this->right_ascension_radians *= degrees_to_radians;
00750     this->declination_radians *= degrees_to_radians;
00751 
00752     comment = "observation wavelength (meters)";
00753     iof.read_key("WVLNGTH", this->wavelength_meters, comment);
00754 
00755     this->pixel_amp_array<precision>::read(iof);
00756 
00757   }
00758 
00759   template<class precision>
00760   void basic_observation<precision>::write(const char * filename) const {
00761     iofits iof;
00762     try{iof.create(filename);}
00763     catch(...){
00764       cerr << "basic_observation::write - "
00765            << "error opening file " << filename << endl;
00766       throw(string("basic_observation::write"));
00767     }
00768     try{this->write(iof);}
00769     catch(...){
00770       cerr << "basic_observation::write - "
00771            << "error writing " 
00772            << this->unique_name() << " to file "
00773            << filename << endl;
00774       throw(string("basic_observation::write"));
00775     }
00776   }
00777 
00778   template<class precision>
00779   void basic_observation<precision>::write(iofits & iof) const {
00780 
00781     double radians_to_degrees = 180./M_PI;
00782 
00783     fits_header_data<double> fhd(this->get_axes());
00784     fhd.write(iof);
00785     string type = this->unique_name();
00786     string comment = "object type";
00787     iof.write_key("TYPE", type, comment);
00788 
00789     iof.write_key("RADECSYS", string("FK4"), string("SYSTEM OF REF. COORD"));
00790     iof.write_key("EQUINOX", (long)2000, string("EQUINOX OF REF. COORD"));
00791     iof.write_key("CTYPE1", string("RA---TAN"), string("AXIS TYPE"));
00792     iof.write_key("CTYPE2", string("DEC--TAN"), string("AXIS TYPE"));
00793     iof.write_key("CD001001", (long)1, string("UNITLESS"));
00794     iof.write_key("CD002001", (long)0, string("UNITLESS"));
00795     iof.write_key("CD001002", (long)0, string("UNITLESS"));
00796     iof.write_key("CD002002", (long)1, string("UNITLESS"));
00797     iof.write_key("CDELT1", -1*this->pixel_scale_radians_per_pixel*radians_to_degrees, string("DEGREES/PIXEL"));
00798     iof.write_key("CDELT2", this->pixel_scale_radians_per_pixel*radians_to_degrees, string("DEGREES/PIXEL"));
00799     iof.write_key("CRPIX1", (long)(this->get_axes()[1]/2), string("REFERENCE PIXEL IN X"));
00800     iof.write_key("CRPIX2", (long)(this->get_axes()[0]/2), string("REFERENCE PIXEL IN Y"));
00801     iof.write_key("CRVAL1", this->right_ascension_radians*radians_to_degrees, string("R.A. (DEGREES)"));
00802     iof.write_key("CRVAL2", this->declination_radians*radians_to_degrees, string("DEC. (DEGREES)"));
00803 
00804     comment = "observation wavelength (meters)";
00805     iof.write_key("WVLNGTH", this->wavelength_meters, comment);
00806 
00807     this->pixel_amp_array<precision>::write(iof);
00808   }
00809 
00810   template<class precision>
00811   void basic_observation<precision>::
00812   print(ostream & os, const char * prefix) const {
00813     int vlspc = 30;
00814     os.setf(ios::left, ios::adjustfield); 
00815     os << prefix << "TYPE       = " << setw(vlspc) << this->unique_name()
00816        << "/" << "object type" << endl;
00817     fits_header_data<double> fhd(this->get_axes());
00818     fhd.print(os, prefix);
00819     os << prefix << "RA         = " << setw(vlspc) << this->right_ascension_radians
00820        << "/" << "right ascension (radians)" << endl;
00821 
00822     os << prefix << "DEC        = " << setw(vlspc) << this->declination_radians
00823        << "/" << "declination (radians)" << endl;
00824 
00825     os << prefix << "PIXSCALE   = " << setw(vlspc) << this->pixel_scale_radians_per_pixel
00826        << "/" << "pixel scale (radians)" << endl;
00827 
00828     os << prefix << "WVLNGTH    = " << setw(vlspc) << this->wavelength_meters
00829        << "/" << "wavelength (meters)" << endl;
00830 
00831   }
00832 
00833 
00834   template<class precision>
00835     vector<pair<double, double> > 
00836     basic_observation<precision>::ensquared_energy() const {
00837 
00838     vector<long> axes = this->get_axes();
00839     int extrapix = 1;
00840     double halfpix = 0;
00841     if(axes[0]%2==0){
00842       extrapix = 0;
00843       halfpix = .5;
00844     }
00845 
00846     int min_slit_width_pixels = extrapix==0 ? 2 : 1;
00847     int max_slit_width_pixels = axes[0];
00848 
00849     int upper_left_index, upper_right_index, lower_left_index, lower_right_index;
00850     double ensquared_energy = 0;
00851 
00852     vector<pair<double, double> > slit_widths_and_EEs;
00853 
00854     for(int k=min_slit_width_pixels; k<max_slit_width_pixels; k+=2){
00855       
00856       if(k==1) 
00857         ensquared_energy += this->pixel_amp_array<double>::pixeldata[(axes[0]+1)*(axes[0]/2)];
00858       else {
00859         upper_left_index = ((axes[0]-k)/2)*(axes[0]+1);
00860         upper_right_index = upper_left_index + (k-1);
00861         lower_left_index = upper_left_index + axes[0]*(k-1);
00862         lower_right_index = lower_left_index + (k-1);
00863             
00864         for(int m=upper_left_index; m<=upper_right_index; m++){
00865           ensquared_energy += this->pixel_amp_array<double>::pixeldata[m];
00866         }
00867         
00868         for(int m=1; m<=(k-2); m++){
00869           ensquared_energy += this->pixel_amp_array<double>::pixeldata[upper_left_index+axes[0]*m];
00870           ensquared_energy += this->pixel_amp_array<double>::pixeldata[upper_right_index+axes[0]*m];
00871         }
00872         
00873         for(int m=lower_left_index; m<=lower_right_index; m++){
00874           ensquared_energy += this->pixel_amp_array<double>::pixeldata[m];
00875         }
00876       }
00877       slit_widths_and_EEs.push_back(pair<double,double>(k*this->pixel_scale_radians_per_pixel, 
00878                                                         ensquared_energy));
00879       
00880     }
00881     return(slit_widths_and_EEs);
00882   }
00883 
00884   /*
00885   template<typename precision>
00886     void basic_observation<precision>::
00887     (int otf_dimen,
00888               double aperture_diameter_meters,
00889               pixel_amp_array<precision> & OTF_amps,
00890               pixel_phase_array<precision> & OTF_phases) const {
00891 
00892     try{
00893      if(otf_dimen<=0){
00894         cerr << "basic_observation::basic_otf error - OTF dimension "
00895              << otf_dimen
00896              << " out of range\n";
00897         throw(string("basic_observation::basic_otf"));
00898       }
00899      if(aperture_diameter_meters<=0){
00900         cerr << "basic_observation::basic_otf error - aperture diameter "
00901              << aperture_diameter_meters
00902              << " out of range\n";
00903         throw(string("basic_observation::basic_otf"));
00904       }
00905 
00906      // set up the storage
00907      vector<long> otf_axes(2, otf_dimen);
00908      
00909      int notf_elems = otf_axes[0]*otf_axes[1];
00910      int npsf_elems = this->axes[0]*this->axes[1];
00911      precision *otf_data;
00912      precision *psf_data;    
00913      try{
00914        otf_data = new precision[2*notf_elems];
00915        psf_data = new precision[2*npsf_elems];
00916      } catch(...) {
00917        cerr << "wavefront_phase_estimate::point_spread_function - error allocating memory\n";
00918         throw(string("wavefront_phase_estimate::point_spread_function"));
00919       }
00920 
00921       // Slope correction for even dimension arrays
00922       double xslope = this->axes[1]%2==1 ? 0 : M_PI/(double)(otf_axes[1]/2);
00923       double yslope = this->axes[0]%2==1 ? 0 : M_PI/(double)(otf_axes[0]/2);
00924 
00925       // Halfpixel information
00926       double psf_x_halfpix=0, psf_y_halfpix=0;
00927       int psf_x_extrapix=1, psf_y_extrapix=1;
00928       if(this->axes[1]%2==0){
00929         psf_x_halfpix = .5;
00930         psf_x_extrapix = 0;
00931       }
00932       if(this->axes[0]%2==0){
00933         psf_y_halfpix = .5;
00934         psf_y_extrapix = 0;
00935       }
00936       double otf_x_halfpix=0, otf_y_halfpix=0;
00937       int otf_x_extrapix=1, otf_y_extrapix=1;
00938       if(otf_axes[1]%2==0){
00939         otf_x_halfpix = .5;
00940         otf_x_extrapix = 0;
00941       }
00942       if(otf_axes[0]%2==0){
00943         otf_y_halfpix = .5;
00944         otf_y_extrapix = 0;
00945       }
00946 
00947       // Initialize the complex PSF data array
00948       int index;
00949       double twopi = 2*M_PI;
00950       double amp, phase;
00951       for(int i=-this->axes[1]/2; i<this->axes[1]/2+psf_x_extrapix; i++){
00952         for(int j=-this->axes[0]/2; j<this->axes[0]/2+psf_y_extrapix; j++){
00953           index = (i+this->axes[1]/2)*this->axes[0]+j+this->axes[0]/2;
00954           amp = this->pixeldata[index];
00955           phase = fmod(-xslope*(i+psf_x_halfpix) - yslope*(j+psf_y_halfpix), twopi);
00956           psf_data[2*index] = amp*cos(phase);
00957           psf_data[2*index+1] = amp*sin(phase);
00958         }
00959       }
00960 
00961       double oversampling_factor = 
00962         wavelength_meters / pixel_scale_radians_per_pixel / aperture_diameter_meters;
00963 
00964       //cerr << "oversampling factor " << oversampling_factor << endl;
00965 
00966       //double sampling_factor = 2/(double)this->axes[0]/oversampling_factor;
00967       double sampling_factor = 2/(double)otf_axes[0]/oversampling_factor;
00968 
00969       goertzel_reinsch_transform(this->axes, otf_axes, sampling_factor, psf_data, otf_data);
00970 
00971       delete [] psf_data;
00972 
00973       OTF_amps = pixel_amp_array<precision>(otf_axes);
00974       OTF_phases = pixel_phase_array<precision>(otf_axes);
00975 
00976       for(int i=0; i<notf_elems; i++){
00977         amp = sqrt(otf_data[2*i]*otf_data[2*i]+otf_data[2*i+1]*otf_data[2*i+1]);
00978         phase = atan2(otf_data[2*i+1],otf_data[2*i]);
00979         OTF_amps.set_data(i, amp);
00980         OTF_phases.set_data(i, phase);
00981       }
00982     } catch(...) {
00983       cerr << "basic_observation::basic_otf error\n";
00984       throw(string("basic_observation::basic_otf"));
00985     }
00986   }
00987   */
00988 
00989 
00990 
00991 
00992 
00993 
00994 
00995 
00996 
00997 
00998 
00999 
01000 
01001 
01002 
01003   template<class precision>
01004     basic_otf<precision>::
01005     basic_otf(){
01006 
01007     this->OTF_amps = pixel_amp_array<precision>(vector<long>(2,0));
01008     this->OTF_phases = pixel_phase_array<precision>(vector<long>(2,0));
01009     
01010     this->right_ascension_radians = 0;
01011     this->declination_radians = 0;
01012     this->pupil_plane_pixel_scale_meters = -1;
01013     this->wavelength_meters = -1;
01014   }
01015 
01016   template<class precision>
01017     basic_otf<precision>::
01018     basic_otf(double ra_radians,
01019               double dec_radians,
01020               double pupil_plane_pixscale_meters,
01021               double wavelength_meters,
01022               const pixel_amp_array<precision> & otf_amps,
01023               const pixel_phase_array<precision> & otf_phases){
01024     
01025     this->right_ascension_radians = ra_radians;
01026     this->declination_radians = dec_radians;
01027     this->pupil_plane_pixel_scale_meters = pupil_plane_pixscale_meters;
01028     this->wavelength_meters = wavelength_meters;
01029 
01030     this->OTF_amps = otf_amps;
01031     this->OTF_phases = otf_phases;
01032 
01033   }
01034 
01035 
01036   template<typename precision>
01037     basic_otf<precision>::basic_otf(double aperture_diameter_meters,
01038                                     double pupil_plane_pixscale_meters,
01039                                     const basic_observation<precision> & basic_obs) {
01040     
01041 
01042     try{
01043       
01044       if(aperture_diameter_meters<=0){
01045         cerr << "basic_otf::basic_otf error - pupil plane pixel scale "
01046              << aperture_diameter_meters
01047              << " out of range\n";
01048         throw(string("basic_otf::basic_otf"));
01049       }
01050       if(pupil_plane_pixscale_meters<=0){
01051         cerr << "basic_otf::basic_otf error - pupil plane pixel scale "
01052              << pupil_plane_pixscale_meters
01053              << " out of range\n";
01054         throw(string("basic_otf::basic_otf"));
01055       }
01056 
01057       this->wavelength_meters = basic_obs.get_wavelength();
01058       this->pupil_plane_pixel_scale_meters = pupil_plane_pixscale_meters;
01059 
01060       // set up the storage
01061       int otf_dimen = (int)ceil(2*aperture_diameter_meters/pupil_plane_pixscale_meters);
01062       if(otf_dimen%2==0) otf_dimen++;
01063       vector<long> otf_axes(2,otf_dimen);
01064       vector<long> psf_axes = basic_obs.get_axes();
01065       
01066       int notf_elems = otf_dimen*otf_dimen;
01067       int npsf_elems = psf_axes[0]*psf_axes[1];
01068       precision *otf_data;
01069       precision *psf_data;    
01070       try{
01071         otf_data = new precision[2*notf_elems];
01072         psf_data = new precision[2*npsf_elems];
01073       } catch(...) {
01074         cerr << "basic_otf::basic_otf - error allocating memory\n";
01075         throw(string("basic_otf::basic_otf"));
01076       }
01077       
01078       // Slope correction for even dimension arrays
01079       double xslope = otf_axes[1]%2==1 ? 0 : M_PI/(double)(psf_axes[1]);
01080       double yslope = otf_axes[0]%2==1 ? 0 : M_PI/(double)(psf_axes[0]);
01081 
01082       // Halfpixel information
01083       double otf_x_halfpix=0, otf_y_halfpix=0;
01084       int otf_x_extrapix=1, otf_y_extrapix=1;
01085       if(otf_axes[1]%2==0){
01086         otf_x_halfpix = .5;
01087         otf_x_extrapix = 0;
01088       }
01089       if(otf_axes[0]%2==0){
01090         otf_y_halfpix = .5;
01091         otf_y_extrapix = 0;
01092       }
01093       double psf_x_halfpix=0, psf_y_halfpix=0;
01094       int psf_x_extrapix=1, psf_y_extrapix=1;
01095       if(psf_axes[1]%2==0){
01096         psf_x_halfpix = .5;
01097         psf_x_extrapix = 0;
01098       }
01099       if(psf_axes[0]%2==0){
01100         psf_y_halfpix = .5;
01101         psf_y_extrapix = 0;
01102       }
01103 
01104       // Initialize the complex PSF data array
01105       int index;
01106       double twopi = 2*M_PI;
01107       double amp, phase;
01108       for(int i=-psf_axes[1]/2; i<psf_axes[1]/2+psf_x_extrapix; i++){
01109         for(int j=-psf_axes[0]/2; j<psf_axes[0]/2+psf_y_extrapix; j++){
01110           index = (i+psf_axes[1]/2)*psf_axes[0]+j+psf_axes[0]/2;
01111           amp = basic_obs.data(index);
01112           phase = (i+psf_x_halfpix)*xslope + (j+psf_y_halfpix)*yslope;
01113           psf_data[2*index] = amp*cos(phase);
01114           psf_data[2*index+1] = amp*sin(phase);
01115         }
01116       }
01117 
01118       /*
01119       double oversampling_factor = 
01120         wavelength_meters / pixel_scale_radians_per_pixel / aperture_diameter_meters;
01121       double sampling_factor = 2/(double)otf_axes[0]/oversampling_factor;
01122       */
01123 
01124       double oversampling_factor = 
01125         wavelength_meters / basic_obs.get_pixel_scale() / aperture_diameter_meters;
01126       double sampling_factor = 2/(double)otf_axes[0]/oversampling_factor;
01127       //double sampling_factor = 1/(double)psf_axes[0]/oversampling_factor;
01128 
01129       goertzel_reinsch_transform(psf_axes, otf_axes, sampling_factor, psf_data, otf_data);
01130 
01131       delete [] psf_data;
01132 
01133       this->OTF_amps = pixel_amp_array<precision>(vector<long>(2,otf_dimen));
01134       this->OTF_phases = pixel_phase_array<precision>(vector<long>(2,otf_dimen));
01135 
01136       double nyquist_pixel_scale_radians_per_pixel = 
01137         basic_obs.get_wavelength() / (double) (otf_axes[0]/2) / this->pupil_plane_pixel_scale_meters;
01138       double fac = basic_obs.get_pixel_scale()/nyquist_pixel_scale_radians_per_pixel;
01139 
01140       xslope = psf_axes[1]%2==1 ? 0 : -2*M_PI*fac/(double)otf_axes[1];
01141       yslope = psf_axes[0]%2==1 ? 0 : -2*M_PI*fac/(double)otf_axes[0];
01142 
01143       for(int i=-otf_axes[1]/2; i<otf_axes[1]/2+otf_x_extrapix; i++){
01144         for(int j=-otf_axes[0]/2; j<otf_axes[0]/2+otf_y_extrapix; j++){
01145           index = (i+otf_axes[1]/2)*otf_axes[0]+j+otf_axes[0]/2;
01146           amp = sqrt(otf_data[2*index]*otf_data[2*index] + otf_data[2*index+1]*otf_data[2*index+1]);
01147           phase = fmod(atan2(otf_data[2*index+1],otf_data[2*index]) -
01148                        xslope*(i+otf_x_halfpix) - 
01149                        yslope*(j+otf_y_halfpix), twopi);
01150           this->OTF_amps.set_data(index, amp);
01151           this->OTF_phases.set_data(index, phase);
01152         }
01153       }
01154 
01155       delete [] otf_data;
01156 
01157       } catch(...) {
01158       cerr << "basic_otf::basic_otf error\n";
01159       throw(string("basic_otf::basic_otf"));
01160     }
01161   }
01162 
01163 
01164   template<class precision>
01165   basic_otf<precision> & basic_otf<precision>::
01166   operator=(const basic_otf<precision> & otf){
01167     if(this==&otf)
01168       return(*this);
01169 
01170     this->right_ascension_radians = otf.right_ascension_radians;
01171     this->declination_radians = otf.declination_radians;
01172     this->pupil_plane_pixel_scale_meters = otf.pupil_plane_pixel_scale_meters;
01173     this->wavelength_meters = otf.wavelength_meters;
01174 
01175     this->OTF_amps = otf.OTF_amps;
01176     this->OTF_phases = otf.OTF_phases;
01177 
01178     return(*this);
01179   }
01180 
01181   template<class precision>
01182   void basic_otf<precision>::read(const char * filename){
01183     iofits iof;
01184     try{iof.open(filename);}
01185     catch(...){
01186       cerr << "basic_otf::read - "
01187            << "error opening file " << filename << endl;
01188       throw(string("basic_otf::read"));
01189     }
01190     try{this->read(iof);}
01191     catch(...){
01192       cerr << "basic_otf::read - "
01193            << "error reading "
01194            << this->unique_name() << " from file "
01195            << filename << endl;
01196       throw(string("basic_otf::read"));
01197     }
01198   }
01199 
01200   template<class precision>
01201   void basic_otf<precision>::read(const iofits & iof){
01202 
01203     if(!iof.key_exists("TYPE")){
01204       cerr << "basic_otf::read error - "
01205            << "unrecognized type of file\n";
01206       iof.print_header(cerr, "hdr dump");
01207       cerr << "hdu num " << iof.get_hdu_num() << " of "
01208            << iof.get_num_hdus() << endl;
01209       throw(string("basic_otf::read"));
01210     }
01211 
01212     string type, comment;
01213     iof.read_key("TYPE", type, comment);
01214     if(type!=this->unique_name()){
01215       cerr << "basic_otf::read error - file of type " 
01216            << type << " rather than of type "
01217            << this->unique_name() << endl;
01218       throw(string("basic_otf::read"));
01219     }
01220 
01221     iof.read_key("PIXSCALE", this->pupil_plane_pixel_scale_meters, comment);
01222     iof.read_key("CRVAL1", this->right_ascension_radians, comment);
01223     iof.read_key("CRVAL2", this->declination_radians, comment);
01224 
01225     double radians_to_degrees = 180./M_PI;
01226     double degrees_to_radians = M_PI/180.;
01227 
01228     comment = "observation wavelength (meters)";
01229     iof.read_key("WVLNGTH", this->wavelength_meters, comment);
01230 
01231     this->OTF_amps.read(iof);
01232 
01233     this->OTF_phases.read(iof);
01234 
01235   }
01236 
01237   template<class precision>
01238   void basic_otf<precision>::write(const char * filename) const {
01239     iofits iof;
01240     try{iof.create(filename);}
01241     catch(...){
01242       cerr << "basic_otf::write - "
01243            << "error opening file " << filename << endl;
01244       throw(string("basic_otf::write"));
01245     }
01246     try{this->write(iof);}
01247     catch(...){
01248       cerr << "basic_otf::write - "
01249            << "error writing " 
01250            << this->unique_name() << " to file "
01251            << filename << endl;
01252       throw(string("basic_otf::write"));
01253     }
01254   }
01255 
01256   template<class precision>
01257   void basic_otf<precision>::write(iofits & iof) const {
01258 
01259     double radians_to_degrees = 180./M_PI;
01260 
01261     fits_header_data<double> fhd(this->OTF_amps.get_axes());
01262     fhd.write(iof);
01263     string type = this->unique_name();
01264     string comment = "object type";
01265     iof.write_key("TYPE", type, comment);
01266 
01267     comment = "pupil plane pixel scale (meters)";
01268     iof.write_key("PIXSCALE", this->pupil_plane_pixel_scale_meters, comment);
01269     iof.write_key("CRVAL1", this->right_ascension_radians*radians_to_degrees, string("R.A. (DEGREES)"));
01270     iof.write_key("CRVAL2", this->declination_radians*radians_to_degrees, string("DEC. (DEGREES)"));
01271 
01272     comment = "observation wavelength (meters)";
01273     iof.write_key("WVLNGTH", this->wavelength_meters, comment);
01274 
01275     this->OTF_amps.write(iof);
01276 
01277     fhd.write(iof);
01278     this->OTF_phases.write(iof);
01279   }
01280 
01281   template<class precision>
01282   void basic_otf<precision>::
01283   print(ostream & os, const char * prefix) const {
01284     int vlspc = 30;
01285     os.setf(ios::left, ios::adjustfield); 
01286     os << prefix << "TYPE       = " << setw(vlspc) << this->unique_name()
01287        << "/" << "object type" << endl;
01288     fits_header_data<double> fhd(this->OTF_amps.get_axes());
01289     fhd.print(os, prefix);
01290     os << prefix << "RA         = " << setw(vlspc) << this->right_ascension_radians
01291        << "/" << "right ascension (radians)" << endl;
01292 
01293     os << prefix << "DEC        = " << setw(vlspc) << this->declination_radians
01294        << "/" << "declination (radians)" << endl;
01295 
01296     os << prefix << "PIXSCALE   = " << setw(vlspc) << this->pupil_plane_pixel_scale_meters
01297        << "/" << "pupil plane pixel scale (meters)" << endl;
01298 
01299     os << prefix << "WVLNGTH    = " << setw(vlspc) << this->wavelength_meters
01300        << "/" << "wavelength (meters)" << endl;
01301 
01302   }
01303 
01304   template<class precision>
01305   basic_otf<precision> & 
01306     basic_otf<precision>::operator*=(const basic_otf<precision> & rhs){
01307 
01308     if(this->get_axes()!=rhs.get_axes()){
01309       cerr << "basic_otf<precision>::operator*= error - mismatched axes\n";
01310       this->print(cerr, "lhs ");
01311       rhs.print(cerr, "rhs ");
01312       throw(string("basic_otf<precision>::operator*="));
01313     }
01314     vector<long> axes = rhs.get_axes();
01315     int nelems = axes[0]*axes[1];
01316     complex<precision> cmp;
01317     for(int i=0; i<nelems; i++){
01318       if(abs(this->data(i))!=0  && abs(rhs.data(i))!=0)
01319         this->set_data(i, this->data(i)*rhs.data(i));
01320       else
01321         this->set_data(i,0);
01322     }
01323   }
01324 
01325   template<class precision>
01326   basic_otf<precision> & 
01327     basic_otf<precision>::operator/=(const basic_otf<precision> & rhs){
01328 
01329     if(this->get_axes()!=rhs.get_axes()){
01330       cerr << "basic_otf<precision>::operator/= error - mismatched axes\n";
01331       this->print(cerr, "lhs ");
01332       rhs.print(cerr, "rhs ");
01333       throw(string("basic_otf<precision>::operator/="));
01334     }
01335     vector<long> axes = rhs.get_axes();
01336     int nelems = axes[0]*axes[1];
01337     for(int i=0; i<nelems; i++){
01338       if(abs(this->data(i))!=0)
01339         this->set_data(i, this->data(i)/rhs.data(i));
01340       else
01341         this->set_data(i,0);
01342     }
01343   }
01344 
01345   template<class precision>
01346   basic_otf<precision> & 
01347     basic_otf<precision>::operator*=(double fac){
01348     this->OTF_amps *= fac;
01349   }
01350 
01351   template<class precision>
01352   basic_otf<precision> & 
01353     basic_otf<precision>::operator+=(const basic_otf<precision> & rhs){
01354 
01355     if(this->get_axes()!=rhs.get_axes()){
01356       cerr << "basic_otf<precision>::operator+= error - mismatched axes\n";
01357       this->print(cerr, "lhs ");
01358       rhs.print(cerr, "rhs ");
01359       throw(string("basic_otf<precision>::operator+="));
01360     }
01361     vector<long> axes = rhs.get_axes();
01362     int nelems = axes[0]*axes[1];
01363     for(int i=0; i<nelems; i++)
01364       this->set_data(i, this->data(i)+rhs.data(i));
01365   }
01366 
01367   template<class precision>
01368   basic_otf<precision> & 
01369     basic_otf<precision>::operator-=(const basic_otf<precision> & rhs){
01370 
01371     if(this->get_axes()!=rhs.get_axes()){
01372       cerr << "basic_otf<precision>::operator+= error - mismatched axes\n";
01373       this->print(cerr, "lhs ");
01374       rhs.print(cerr, "rhs ");
01375       throw(string("basic_otf<precision>::operator+="));
01376     }
01377     vector<long> axes = rhs.get_axes();
01378     int nelems = axes[0]*axes[1];
01379     for(int i=0; i<nelems; i++)
01380       this->set_data(i, this->data(i)-rhs.data(i));
01381   }
01382 
01383   template <class precision> 
01384     basic_otf<precision> operator * (const basic_otf<precision> &p1, 
01385                                      double & fac){
01386     basic_otf<precision> tmp(p1);
01387     tmp.operator*=(fac);
01388     return(tmp);
01389   }
01390 
01391   template <class precision> 
01392     basic_otf<precision> operator * (const basic_otf<precision> &p1, 
01393                                      const basic_otf<precision> &p2){
01394     basic_otf<precision> tmp(p1);
01395     tmp.operator*=(p2);
01396     return(tmp);
01397   }
01398 
01399   template <class precision> 
01400     basic_otf<precision> operator / (const basic_otf<precision> &p1, 
01401                                      const basic_otf<precision> &p2){
01402     basic_otf<precision> tmp(p1);
01403     tmp.operator/=(p2);
01404     return(tmp);
01405   }
01406 
01407   template <class precision> 
01408     basic_otf<precision> operator + (const basic_otf<precision> &p1, 
01409                                      const basic_otf<precision> &p2){
01410     basic_otf<precision> tmp(p1);
01411     tmp.operator+=(p2);
01412     return(tmp);
01413   }
01414 
01415   template <class precision> 
01416     basic_otf<precision> operator - (const basic_otf<precision> &p1, 
01417                                      const basic_otf<precision> &p2){
01418     basic_otf<precision> tmp(p1);
01419     tmp.operator-=(p2);
01420     return(tmp);
01421   }
01422 
01423 }
01424 #endif

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