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

arroyo_least_squares_reconstructor.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 ARROYO_LEAST_SQUARES_RECONSTRUCTOR_H
00032 #define ARROYO_LEAST_SQUARES_RECONSTRUCTOR_H
00033 
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <unistd.h>
00037 #include <iostream>
00038 #include <region_base.h>
00039 #include <linear_algebra.h>
00040 #include "zernike_projected_zonal_reconstructor.h"
00041 #include "aperture.h"
00042 #include "lenslet_array.h"
00043 
00044 namespace Arroyo {
00048 
00049   template<class T>
00050   class arroyo_least_squares_reconstructor :
00051     public zernike_projected_zonal_reconstructor,
00052     public Arroyo::pixel_array<T> {
00053 
00054     private:
00055 
00056     static const bool factory_registration;
00057 
00060     std::string unique_name() const {return(std::string("arroyo least squares reconstructor"));};
00061 
00062     protected:
00063 
00065     vector<long> actuator_axes;
00066 
00068     vector<long> centroid_axes;
00069 
00071     zernike projected_modes;
00072 
00073     // A flag to indicate whether the eigenmodes were preserved
00074     // when the reconstructor was generated
00075     bool eigenmodes_stored_in_instance;
00076 
00077     // The eigenvalue threshold used in forming the reconstructor
00078     double eigenvalue_threshold;
00079 
00080     // A flag to indicate whether the geometry matrix was preserved
00081     // when the reconstructor was generated
00082     bool geometry_matrix_stored_in_instance;
00083 
00084     // A flag to indicate whether the A++ sign convention is used
00085     bool app_sign_convention;
00086 
00087     // The subap illumination threshold used in forming the reconstructor
00088     double subaperture_illumination_threshold;
00089 
00091     pixel_array<T> geometry_matrix;
00092 
00094     pixel_array<T> g_gtranspose_eigenmodes;
00095     
00097     pixel_array<T> gtranspose_g_eigenmodes;
00098 
00100     pixel_array<T> sqrt_eigenvalues;
00101 
00102 
00105     arroyo_least_squares_reconstructor(){};
00106 
00107     public:
00108 
00111     arroyo_least_squares_reconstructor(const arroyo_least_squares_reconstructor & arroyo_lsq_recon);
00112 
00115     arroyo_least_squares_reconstructor(const char * filename);
00116 
00119     arroyo_least_squares_reconstructor(const Arroyo::iofits & iof);
00120 
00149     template<class aperture_type, class dm_ap>
00150     arroyo_least_squares_reconstructor(const aperture_type & ap, 
00151                                        const ideal_deformable_mirror<dm_ap> & idm,
00152                                        const square_lenslet_array & sq_lnslt_arr,
00153                                        const zernike & projection_modes,
00154                                        bool modal_projection_in_actuator_space,
00155                                        double subaperture_illumination_threshold,
00156                                        double eigenvalue_threshold,
00157                                        bool aplusplus_sign_convention = false,
00158                                        bool store_eigenmodes = false,
00159                                        bool store_geometry_matrix = false);
00160 
00163     ~arroyo_least_squares_reconstructor(){};
00164 
00167     arroyo_least_squares_reconstructor & 
00168       operator=(const arroyo_least_squares_reconstructor & arroyo_lsq_recon);
00169 
00172     void read(const char * filename);
00173 
00176     void read(const Arroyo::iofits & iof);
00177 
00180     void write(const char * filename) const;
00181  
00184     void write(Arroyo::iofits & iof) const;
00185  
00188     void print(std::ostream & os, const char * prefix="") const;
00189 
00193     double get_eigenvalue_threshold() const;
00194 
00198     double get_subaperture_illumination_threshold() const;
00199 
00203     vector<long> get_centroid_axes() const;
00204 
00208     vector<long> get_actuator_axes() const;
00209 
00218     Arroyo::zernike get_zernike_modes() const;
00219 
00222     bool geometry_matrix_stored() const;
00223 
00226     bool eigenmodes_stored() const;
00227 
00234     pixel_array<T> get_geometry_matrix() const;
00235 
00241     int get_nactuator_eigenmodes() const;
00242 
00248     int get_ncentroid_eigenmodes() const;
00249 
00259     double get_eigenvalue(int mode_number) const;
00260 
00270     template<class U>
00271     double get_actuator_eigenmode(int mode_number, 
00272                                   pixel_array<U> & actuator_mode) const;
00273 
00283     double get_centroid_eigenmode(int mode_number, 
00284                                   Shack_Hartmann_centroids & centroid_mode) const;
00285 
00292     void reconstruct_zernike_residuals(const Arroyo::Shack_Hartmann_centroids & shcentroids, 
00293                                        Arroyo::zernike & znke) const;
00294 
00298     void reconstruct_zonal_residuals(const Arroyo::Shack_Hartmann_centroids & shcentroids, 
00299                                      Arroyo::pixel_array<double> & pixarr) const;
00300 
00308     void reconstruct_residuals(const Arroyo::Shack_Hartmann_centroids & shcentroids, 
00309                                Arroyo::zernike & znke, 
00310                                Arroyo::pixel_array<double> & pixarr) const;
00311   };
00312 
00313   template<class T> 
00314   arroyo_least_squares_reconstructor<T>::
00315   arroyo_least_squares_reconstructor(const arroyo_least_squares_reconstructor & arroyo_lsq_recon){
00316     this->operator=(arroyo_lsq_recon);
00317   }
00318 
00319   template<class T> 
00320   arroyo_least_squares_reconstructor<T>::
00321   arroyo_least_squares_reconstructor(const char * filename){
00322     this->axes.resize(2);
00323     this->read(filename);
00324   }
00325 
00326   template<class T> 
00327   arroyo_least_squares_reconstructor<T>::
00328   arroyo_least_squares_reconstructor(const iofits & iof){
00329     this->axes.resize(2);
00330     this->read(iof);
00331   }
00332 
00333   template<class T> 
00334   arroyo_least_squares_reconstructor<T> & 
00335   arroyo_least_squares_reconstructor<T>::
00336   operator=(const arroyo_least_squares_reconstructor & arroyo_lsq_recon){
00337     if(this==&arroyo_lsq_recon)
00338       return(*this);
00339     actuator_axes = arroyo_lsq_recon.actuator_axes;
00340     centroid_axes = arroyo_lsq_recon.centroid_axes;
00341     projected_modes = arroyo_lsq_recon.projected_modes;
00342     eigenmodes_stored_in_instance = arroyo_lsq_recon.eigenmodes_stored_in_instance;
00343     geometry_matrix_stored_in_instance = arroyo_lsq_recon.geometry_matrix_stored_in_instance;
00344     geometry_matrix = arroyo_lsq_recon.geometry_matrix;
00345     app_sign_convention = arroyo_lsq_recon.app_sign_convention;
00346     g_gtranspose_eigenmodes = arroyo_lsq_recon.g_gtranspose_eigenmodes; 
00347     gtranspose_g_eigenmodes = arroyo_lsq_recon.gtranspose_g_eigenmodes; 
00348     sqrt_eigenvalues = arroyo_lsq_recon.sqrt_eigenvalues;
00349 
00350     this->pixel_array<T>::operator=(arroyo_lsq_recon);
00351     return(*this);
00352   }
00353 
00354   template<class T> 
00355   void arroyo_least_squares_reconstructor<T>::read(const char * filename){
00356     iofits iof;
00357     try{iof.open(filename);}
00358     catch(...){
00359       cerr << "arroyo_least_squares_reconstructor::read - "
00360            << "error opening file " << filename << endl;
00361       throw(string("arroyo_least_squares_reconstructor::read"));
00362     }
00363     try{this->read(iof);}
00364     catch(...){
00365       cerr << "arroyo_least_squares_reconstructor::read - "
00366            << "error reading "
00367            << this->unique_name() << " from file " 
00368            << filename << endl;
00369       throw(string("arroyo_least_squares_reconstructor::read"));
00370     }
00371   }
00372 
00373   template<class T> 
00374   void arroyo_least_squares_reconstructor<T>::read(const iofits & iof) {
00375     if(!iof.key_exists("TYPE")){
00376       cerr << "arroyo_least_squares_reconstructor::read error - "
00377            << "unrecognized type of file\n";
00378       throw(string("arroyo_least_squares_reconstructor::read"));
00379     }
00380     string type, comment;
00381     iof.read_key("TYPE", type, comment);
00382     if(type!=this->unique_name()){
00383       cerr << "arroyo_least_squares_reconstructor::read error - file of type " 
00384            << type << " rather than of type "
00385            << this->unique_name() << endl;
00386       throw(string("arroyo_least_squares_reconstructor::read"));
00387     }
00388     
00389     actuator_axes.resize(2);
00390     centroid_axes.resize(2);
00391 
00392     iof.read_key("ACTUATR1", actuator_axes[0], comment);
00393     iof.read_key("ACTUATR2", actuator_axes[1], comment);
00394 
00395     iof.read_key("CNTROID1", centroid_axes[0], comment);
00396     iof.read_key("CNTROID2", centroid_axes[1], comment);
00397 
00398     iof.read_key("EGNTHRSH", eigenvalue_threshold, comment);
00399     iof.read_key("SBPTHRSH", subaperture_illumination_threshold, comment);
00400 
00401     if(iof.key_exists("EIGENMDS"))
00402        iof.read_key("EIGENMDS", eigenmodes_stored_in_instance, comment);
00403     else eigenmodes_stored_in_instance = false;
00404 
00405     if(iof.key_exists("GEOMETRY"))
00406       iof.read_key("GEOMETRY", geometry_matrix_stored_in_instance, comment);
00407     else geometry_matrix_stored_in_instance = false;
00408 
00409     if(iof.key_exists("APPSIGN"))
00410       iof.read_key("APPSIGN", app_sign_convention, comment);
00411     else app_sign_convention = false;
00412 
00413     this->pixel_array<T>::read(iof);
00414 
00415     // Work out the number of projected zernike modes, and initialize
00416     // the projected_modes data member
00417     int nelem = this->pixel_array<T>::total_space();
00418     nelem -= actuator_axes[0]*actuator_axes[1]*centroid_axes[0]*centroid_axes[1];
00419     if(nelem%(centroid_axes[0]*centroid_axes[1])!=0){
00420       cerr << "arroyo_least_squares_reconstructor::read error - "
00421            << "unexpected number of elements " << nelem << " in the matrix\n";
00422       throw(string("arroyo_least_squares_reconstructor::read"));
00423     }
00424       
00425     int nmodes = nelem/(centroid_axes[0]*centroid_axes[1]);
00426     int zernike_order = -1;
00427     while(nmodes>0){
00428       zernike_order++;
00429       if(zernike_order%2)
00430         nmodes -= 2*(zernike_order/2+1);
00431       else 
00432         nmodes -= (zernike_order+1);
00433     }
00434 
00435     if(zernike_order>=0)
00436       projected_modes = zernike(zernike_order);
00437 
00438     if(geometry_matrix_stored_in_instance){
00439       try{
00440         geometry_matrix.read(iof);
00441       } catch(...) {
00442         cerr << "arroyo_least_squares_reconstructor::read - error reading geometry matrix\n";
00443         throw(string("arroyo_least_squares_reconstructor::read"));
00444       }
00445     }
00446 
00447     if(eigenmodes_stored_in_instance){
00448 
00449       try{
00450         sqrt_eigenvalues.read(iof);
00451       } catch(...) {
00452         cerr << "arroyo_least_squares_reconstructor::read - error reading eigenvalues\n";
00453         throw(string("arroyo_least_squares_reconstructor::read"));
00454       }
00455 
00456       try{
00457         g_gtranspose_eigenmodes.read(iof);
00458         gtranspose_g_eigenmodes.read(iof);
00459       } catch(...) {
00460         cerr << "arroyo_least_squares_reconstructor::read - error reading GGtranspose matrices\n";
00461         throw(string("arroyo_least_squares_reconstructor::read"));
00462       }
00463     }
00464 
00465     // leave iof pointing to the next header, if it exists
00466     if(iof.get_hdu_num()!=iof.get_num_hdus())
00467       iof.movrel_hdu(1);
00468   }
00469 
00470   template<class T> 
00471   void arroyo_least_squares_reconstructor<T>::write(const char * filename) const {
00472 
00473     iofits iof;
00474     try{iof.create(filename);}
00475     catch(...){
00476       cerr << "arroyo_least_squares_reconstructor::write - "
00477            << "error opening file " << filename << endl;
00478       throw(string("arroyo_least_squares_reconstructor::write"));
00479     }
00480 
00481     try{this->write(iof);}
00482     catch(...){
00483       cerr << "arroyo_least_squares_reconstructor::write - "
00484            << "error writing "
00485            << this->unique_name() << " to file "
00486            << filename << endl;
00487       throw(string("arroyo_least_squares_reconstructor::write"));
00488     }
00489   }
00490 
00491   template<class T> 
00492   void arroyo_least_squares_reconstructor<T>::write(iofits & iof) const {
00493     fits_header_data<T> fhd(this->axes);
00494     fhd.write(iof);
00495     string type = this->unique_name();
00496     string comment = "object type";
00497     iof.write_key("TYPE", type, comment);
00498 
00499     iof.write_key("ACTUATR1", actuator_axes[0], "length of actuator axis 1");
00500     iof.write_key("ACTUATR2", actuator_axes[1], "length of actuator axis 2");
00501 
00502     iof.write_key("CNTROID1", centroid_axes[0], "length of centroid axis 1");
00503     iof.write_key("CNTROID2", centroid_axes[1], "length of centroid axis 2");
00504 
00505     iof.write_key("EGNTHRSH", eigenvalue_threshold, "threshold for keeping eigenvalues");
00506     iof.write_key("SBPTHRSH", subaperture_illumination_threshold, "threshold for keeping partially illuminated subaps");
00507 
00508     iof.write_key("APPSIGN", app_sign_convention, "A++ sign convention");
00509 
00510     if(sqrt_eigenvalues.get_axes().size())
00511       iof.write_key("EIGENMDS", true, "eigenmodes stored");
00512     else 
00513       iof.write_key("EIGENMDS", false, "eigenmodes stored");
00514 
00515     if(geometry_matrix.get_axes().size())
00516       iof.write_key("GEOMETRY", true, "geometry matrix stored");
00517     else
00518       iof.write_key("GEOMETRY", false, "geometry matrix stored");
00519 
00520     this->pixel_array<T>::write(iof);
00521 
00522     if(geometry_matrix.get_axes().size()){
00523       fits_header_data<T> fhd(geometry_matrix.get_axes());
00524       fhd.write(iof);
00525       geometry_matrix.write(iof);
00526     }
00527     
00528     if(sqrt_eigenvalues.get_axes().size()){
00529       fits_header_data<T> fhd1(sqrt_eigenvalues.get_axes());
00530       fhd1.write(iof);
00531       sqrt_eigenvalues.write(iof);
00532 
00533       fits_header_data<T> fhd2(g_gtranspose_eigenmodes.get_axes());
00534       fhd2.write(iof);
00535       g_gtranspose_eigenmodes.write(iof);
00536 
00537       fits_header_data<T> fhd3(gtranspose_g_eigenmodes.get_axes());
00538       fhd3.write(iof);
00539       gtranspose_g_eigenmodes.write(iof);
00540     }
00541   }
00542 
00543   template<class T> 
00544   void arroyo_least_squares_reconstructor<T>::print(ostream & os, const 
00545                                                  char * prefix) const {
00546     int vlspc = 30;
00547     os.setf(std::ios::left, std::ios::adjustfield); 
00548     os << prefix << "TYPE       = " << setw(vlspc) << this->unique_name()
00549        << "/" << "object type" << endl;
00550     fits_header_data<T> fhd(this->axes);
00551     fhd.print(os, prefix);
00552     os << prefix << "ACTUATR1   = " << setw(vlspc) << this->actuator_axes[0]
00553        << "/" << "length of actuator axis 1" << endl;
00554     os << prefix << "ACTUATR2   = " << setw(vlspc) << this->actuator_axes[1]
00555        << "/" << "length of actuator axis 2" << endl;
00556     os << prefix << "CNTROID1   = " << setw(vlspc) << this->centroid_axes[0]
00557        << "/" << "length of centroid axis 1" << endl;
00558     os << prefix << "CNTROID2   = " << setw(vlspc) << this->centroid_axes[1]
00559        << "/" << "length of centroid axis 2" << endl;
00560     os << prefix << "EGNTHRSH   = " << setw(vlspc) << this->eigenvalue_threshold
00561        << "/" << "threshold for keeping eigenvalues" << endl;
00562     os << prefix << "APPSIGN    = " << setw(vlspc) << this->app_sign_convention
00563        << "/" << "A++ sign convention" << endl;
00564     os << prefix << "SBPTHRSH   = " << setw(vlspc) << this->subaperture_illumination_threshold
00565        << "/" << "threshold for keeping partially illuminated subaps" << endl;
00566     os << prefix << "GEOMETRY   = " << setw(vlspc) << this->geometry_matrix_stored_in_instance
00567        << "/" << "geometry matrix storage flag" << endl;
00568     os << prefix << "EIGENMDS   = " << setw(vlspc) << this->eigenmodes_stored_in_instance
00569        << "/" << "eigenmodes storage flag" << endl;
00570   }
00571 
00572   template<class T> 
00573   vector<long> arroyo_least_squares_reconstructor<T>::get_centroid_axes() const {
00574     return(centroid_axes);
00575   }
00576 
00577   template<class T> 
00578   vector<long> arroyo_least_squares_reconstructor<T>::get_actuator_axes() const {
00579     return(actuator_axes);
00580   }
00581 
00582   template<class T> 
00583   zernike arroyo_least_squares_reconstructor<T>::get_zernike_modes() const {
00584     return(projected_modes);
00585   }
00586 
00587   template<class T> 
00588   double arroyo_least_squares_reconstructor<T>::get_eigenvalue_threshold() const {
00589     return(eigenvalue_threshold);
00590   }
00591 
00592   template<class T> 
00593   double arroyo_least_squares_reconstructor<T>::get_subaperture_illumination_threshold() const {
00594     return(subaperture_illumination_threshold);
00595   }
00596 
00597   template<class T> 
00598   int arroyo_least_squares_reconstructor<T>::get_nactuator_eigenmodes() const {
00599     return(actuator_axes[0]*actuator_axes[1]);
00600   }
00601 
00602   template<class T> 
00603   int arroyo_least_squares_reconstructor<T>::get_ncentroid_eigenmodes() const {
00604     return(centroid_axes[0]*centroid_axes[1]);
00605   }
00606 
00607   template<class T>
00608     bool arroyo_least_squares_reconstructor<T>::
00609     geometry_matrix_stored() const {
00610     return(this->geometry_matrix_stored_in_instance);
00611   };
00612 
00613   template<class T>
00614     bool arroyo_least_squares_reconstructor<T>::
00615     eigenmodes_stored() const {
00616     return(this->eigenmodes_stored_in_instance);
00617   };
00618 
00619   template<class T>
00620     pixel_array<T> arroyo_least_squares_reconstructor<T>::
00621     get_geometry_matrix() const {
00622     if(this->geometry_matrix_stored())
00623       return(this->geometry_matrix);
00624     else {
00625       cerr << "arroyo_least_squares_reconstructor::get_geometry_matrix error - " 
00626            << "this class instance generated without saving geometry matrix\n";
00627       throw(string("arroyo_least_squares_reconstructor::get_geometry_matrix"));
00628     }
00629   };
00630 
00631   template<class T> 
00632   double arroyo_least_squares_reconstructor<T>::
00633     get_eigenvalue(int mode_number) const {
00634 
00635     if(!this->eigenmodes_stored_in_instance){
00636       cerr << "arroyo_least_squares_reconstructor::get_eigenvalue error - "
00637            << " this class instance was constructed without saving the eigenmodes\n";
00638       throw(string("arroyo_least_squares_reconstructor::get_eigenvalue"));
00639     }
00640 
00641     if(mode_number<0 || mode_number>this->get_nactuator_eigenmodes()){
00642       cerr << "arroyo_least_squares_reconstructor::get_eigenvalue error - "
00643            << " mode number " << mode_number << " out of range\n";
00644       throw(string("arroyo_least_squares_reconstructor::get_eigenvalue"));
00645     }
00646 
00647     return(sqrt_eigenvalues.data(mode_number)*sqrt_eigenvalues.data(mode_number));
00648   }
00649 
00650   template<class T> 
00651     template<class U>
00652   double arroyo_least_squares_reconstructor<T>::
00653     get_actuator_eigenmode(int mode_number, pixel_array<U> & actuators) const {
00654 
00655     if(!this->eigenmodes_stored_in_instance){
00656       cerr << "arroyo_least_squares_reconstructor::get_actuator_eigenmode error - "
00657            << " this class instance was constructed without saving the eigenmodes\n";
00658       throw(string("arroyo_least_squares_reconstructor::get_actuator_eigenmode"));
00659     }
00660 
00661     if(mode_number<0 || mode_number>this->get_nactuator_eigenmodes()){
00662       cerr << "arroyo_least_squares_reconstructor::get_actuator_eigenmode error - "
00663            << " mode number " << mode_number << " out of range\n";
00664       throw(string("arroyo_least_squares_reconstructor::get_actuator_eigenmode"));
00665     }
00666 
00667     if(actuators.get_axes()!=actuator_axes){
00668       cerr << "arroyo_least_squares_reconstructor::get_actuator_eigenmode error - "
00669            << "pixel array instance passed to this function "
00670            << "has a different dimensionality than expected\n";
00671       cerr << "\texpected " << actuator_axes[0] << "x" << actuator_axes[1] << endl;
00672       cerr << "\tgot " << actuators.get_axes()[0] << "x" << actuators.get_axes()[1] << endl;
00673       throw(string("arroyo_least_squares_reconstructor::get_actuator_eigenmode"));
00674     }
00675 
00676     int nactuators = actuator_axes[0]*actuator_axes[1];
00677     for(int i=0; i<nactuators; i++)
00678       actuators.set_data(i, gtranspose_g_eigenmodes.data(mode_number+i*nactuators));
00679 
00680     return(sqrt_eigenvalues.data(mode_number)*sqrt_eigenvalues.data(mode_number));
00681   }
00682 
00683   template<class T> 
00684   double arroyo_least_squares_reconstructor<T>::
00685     get_centroid_eigenmode(int mode_number, Shack_Hartmann_centroids & shcentroids) const {
00686 
00687     if(!this->eigenmodes_stored_in_instance){
00688       cerr << "arroyo_least_squares_reconstructor::get_centroid_eigenmode error - "
00689            << " this class instance was constructed without saving the eigenmodes\n";
00690       throw(string("arroyo_least_squares_reconstructor::get_centroid_eigenmode"));
00691     }
00692 
00693     if(mode_number<0 || mode_number>this->get_ncentroid_eigenmodes()){
00694       cerr << "arroyo_least_squares_reconstructor::get_centroid_eigenmode error - "
00695            << " mode number " << mode_number << " out of range\n";
00696       throw(string("arroyo_least_squares_reconstructor::get_centroid_eigenmode"));
00697     }
00698 
00699     if(shcentroids.get_axes()!=centroid_axes){
00700       cerr << "arroyo_least_squares_reconstructor::get_centroid_eigenmode error - "
00701            << "Shack Hartmann centroid instance passed to this function "
00702            << "has a different dimensionality than expected\n";
00703       cerr << "\texpected " << centroid_axes[0] << "x" << centroid_axes[1] << endl;
00704       cerr << "\tgot " << shcentroids.get_axes()[0] << "x" << shcentroids.get_axes()[1] << endl;
00705       throw(string("arroyo_least_squares_reconstructor::get_centroid_eigenmode"));
00706     }
00707 
00708     int ncentroids = centroid_axes[0]*centroid_axes[1];
00709     for(int i=0; i<ncentroids; i++)
00710       shcentroids.set_data(i, g_gtranspose_eigenmodes.data(mode_number*ncentroids+i));
00711 
00712     if(mode_number<sqrt_eigenvalues.get_axes()[0])
00713       return(sqrt_eigenvalues.data(mode_number)*sqrt_eigenvalues.data(mode_number));
00714     else 
00715       return(0);
00716   }
00717 
00718   template<class T> 
00719   void arroyo_least_squares_reconstructor<T>::
00720   reconstruct_zernike_residuals(const Arroyo::Shack_Hartmann_centroids & shcentroids, 
00721                                 zernike & znke) const {
00722 
00723     if(shcentroids.total_space()!=this->axes[0]){
00724       cerr << "arroyo_least_squares_reconstructor::reconstruct_zernike_residuals error - "
00725            << " Shack Hartmann centroids instance supplied to this function has " 
00726            << shcentroids.total_space() << " elements, whereas " 
00727            << this->axes[0] << " were expected by the reconstructor\n";
00728       throw(string("arroyo_least_squares_reconstructor::reconstruct_zernike_residuals"));
00729     }
00730 
00731     if(znke.get_order()!=projected_modes.get_order()){
00732       cerr << "arroyo_least_squares_reconstructor::reconstruct_zernike_residuals error - "
00733            << " zernike order supplied to this function " 
00734            << znke.get_order() << " does not match that expected by the reconstructor "
00735            << projected_modes.get_order() << endl;
00736       throw(string("arroyo_least_squares_reconstructor::reconstruct_zernike_residuals"));
00737     }
00738 
00739     // For now, this is implemented for tip and tilt only, as the constructor only handles
00740     // this case.
00741 
00742     int xindex = centroid_axes[0]*centroid_axes[1]*(actuator_axes[0]*actuator_axes[1]+1);
00743     int yindex = xindex + centroid_axes[0]*centroid_axes[1];
00744     double xresid, yresid;
00745     xresid = yresid = 0;
00746     
00747     for(int j=0; j<this->axes[0]; j++){
00748       xresid -= this->pixeldata[xindex+j]*shcentroids.data(j);
00749       yresid -= this->pixeldata[yindex+j]*shcentroids.data(j);
00750     }
00751 
00752     znke.set_cos_coeff(1,1,xresid);
00753     znke.set_sin_coeff(1,1,yresid);
00754   }
00755 
00756   template<class T> 
00757   void arroyo_least_squares_reconstructor<T>::
00758   reconstruct_zonal_residuals(const Arroyo::Shack_Hartmann_centroids & shcentroids, 
00759                               pixel_array<double> & pixarr) const {
00760 
00761     vector<long> pixarr_axes = pixarr.get_axes();
00762     if(pixarr_axes[0]!=actuator_axes[0] || 
00763        pixarr_axes[1]!=actuator_axes[1]){
00764       cerr << "arroyo_least_squares_reconstructor::reconstruct_zonal_residuals error - " << endl
00765            << "pixel array instance passed to reconstructor has axes "
00766            << pixarr_axes[0] << "x" << pixarr_axes[1] 
00767            << " elements, rather than axes " 
00768            << actuator_axes[0] << "x" << actuator_axes[1]
00769            << " expected by this reconstructor\n";
00770       throw(string("arroyo_least_squares_reconstructor::reconstruct_zonal_residuals"));
00771     }
00772 
00773     long index = 0;
00774     double resid;
00775     long nsubaps = centroid_axes[0]*centroid_axes[1]/2;
00776     int nactuators = actuator_axes[0]*actuator_axes[1];
00777     int app_sign = app_sign_convention ? -1 : 1;
00778 
00779     for(int i=0; i<actuator_axes[1]; i++){
00780       for(int j=0; j<actuator_axes[0]; j++){
00781         resid = 0;
00782         for(int k=0; k<nsubaps; k++){
00783 
00784           resid -= app_sign*this->pixeldata[index+k]*shcentroids.data(k);
00785           resid -= this->pixeldata[index+nsubaps+k]*shcentroids.data(k+nsubaps);
00786         }
00787         pixarr.set_data(j*actuator_axes[1]+i, resid);
00788         index += this->axes[0];
00789       }
00790     }
00791   }
00792 
00793   template<class T> 
00794   void arroyo_least_squares_reconstructor<T>::
00795   reconstruct_residuals(const Arroyo::Shack_Hartmann_centroids & shcentroids, 
00796                         zernike & znke, 
00797                         pixel_array<double> & pixarr) const {
00798     this->reconstruct_zernike_residuals(shcentroids, znke);
00799     this->reconstruct_zonal_residuals(shcentroids, pixarr);
00800   }
00801 
00802   template<class T>
00803   template<class pupil_aperture, class dm_aperture>
00804     arroyo_least_squares_reconstructor<T>::
00805     arroyo_least_squares_reconstructor(const pupil_aperture & ap, 
00806                                        const ideal_deformable_mirror<dm_aperture> & ideal_dm,
00807                                        const square_lenslet_array & sq_lnslt_arr,
00808                                        const zernike & projected_modes,
00809                                        bool modal_projection_in_actuator_space,
00810                                        double subaperture_illumination_threshold,
00811                                        double eigenvalue_threshold,
00812                                        bool aplusplus_sign_convention,
00813                                        bool store_eigenmodes,
00814                                        bool store_geometry_matrix){
00815 
00816     this->projected_modes = projected_modes;
00817     this->actuator_axes = ideal_dm.get_axes();
00818     this->centroid_axes = sq_lnslt_arr.get_axes();
00819     this->centroid_axes[1]*=2;
00820     this->subaperture_illumination_threshold = subaperture_illumination_threshold;
00821     this->eigenvalue_threshold = eigenvalue_threshold;
00822     this->eigenmodes_stored_in_instance = store_eigenmodes;
00823     this->geometry_matrix_stored_in_instance = store_geometry_matrix;
00824     this->app_sign_convention = aplusplus_sign_convention;
00825 
00826     // enforce requirement that lenslet array is in the plane of the aperture
00827     if(fabs(sq_lnslt_arr.three_point::z(ap))>three_frame::precision){
00828       cerr << "arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor error - \n"
00829            << "lenslet array does not lie in the plane of the aperture\n";
00830       throw(string("arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor"));      
00831     }
00832 
00833     // enforce requirement that deformable mirror is in the plane of the aperture
00834     if(fabs(ideal_dm.three_point::z(ap))>three_frame::precision){
00835       cerr << "arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor error - \n"
00836            << "deformable mirror does not lie in the plane of the aperture\n";
00837       throw(string("arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor"));      
00838     }
00839 
00840     // enforce requirement that aperture and lenslet array are oriented in the same direction
00841     if(fabs(1-dot_product(ap.z(), sq_lnslt_arr.z()))>three_frame::precision){
00842       cerr << "arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor error - \n"
00843            << "cannot construct reconstructor with aperture and lenslet axes misaligned\n";
00844       throw(string("arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor"));      
00845     }
00846 
00847     // enforce (temporary) requirement that aperture and deformable mirror are oriented in the same direction
00848     if(fabs(1-dot_product(ap.z(), ideal_dm.z()))>three_frame::precision){
00849       cerr << "arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor error - \n"
00850            << "cannot construct reconstructor with aperture and deformable mirror misaligned\n";
00851       throw(string("arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor"));      
00852     }
00853 
00854     if(projected_modes.get_order()>1){
00855       cerr << "arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor error - "
00856            << "projections for modes other than tip and tilt are not yet supported\n";
00857       throw(string("arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor"));
00858     }
00859 
00860     // Check for valid geometry threshold
00861     if(subaperture_illumination_threshold<0 || subaperture_illumination_threshold>1){
00862       cerr << "arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor error - "
00863            << "invalid subaperture illumination threshold " << subaperture_illumination_threshold << endl;
00864       throw(string("arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor"));
00865     }
00866 
00867     // Check for valid eigenvalue threshold
00868     if(eigenvalue_threshold<0 || eigenvalue_threshold>1){
00869       cerr << "arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor error - "
00870            << "invalid eigenvalue threshold " << eigenvalue_threshold << endl;
00871       throw(string("arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor"));
00872     }
00873 
00874     // get lenslet geometry information
00875     three_vector lenslet_array_origin_offset = sq_lnslt_arr - ap;
00876     three_vector lenslet_dx = sq_lnslt_arr.get_lenslet_pitch()*sq_lnslt_arr.x();
00877     three_vector lenslet_dy = sq_lnslt_arr.get_lenslet_pitch()*sq_lnslt_arr.y();
00878     three_vector lenslet_dx_unit_vector = lenslet_dx*(1/lenslet_dx.length());
00879     three_vector lenslet_dy_unit_vector = lenslet_dy*(1/lenslet_dy.length());
00880 
00881     double lenslet_buffer = (lenslet_dy+lenslet_dx).length() > (lenslet_dy-lenslet_dx).length() ? 
00882       .5*(lenslet_dy+lenslet_dx).length() : .5*(lenslet_dy-lenslet_dx).length();
00883 
00884     // get projected actuator spacing
00885     // SIMPLIFYING ASSUMPTION - FIX THIS LATER
00886     three_vector dm_origin_offset = ideal_dm - ap;
00887     three_vector dm_dx = ideal_dm.get_actuator_pitch()*ideal_dm.x();
00888     three_vector dm_dy = ideal_dm.get_actuator_pitch()*ideal_dm.y();
00889 
00890     double dm_buffer = (dm_dy+dm_dx).length() > (dm_dy-dm_dx).length() ? 
00891       .5*(dm_dy+dm_dx).length() : .5*(dm_dy-dm_dx).length();
00892 
00893     double geometry_matrix_buffer = 2*(lenslet_buffer+dm_buffer)*(lenslet_buffer+dm_buffer);
00894 
00895     // The lenslet array halfpixel information
00896     vector<long> lenslet_axes = sq_lnslt_arr.get_axes();
00897     double lenslet_x_halfpix = lenslet_axes[1]%2==1 ? 0 : .5;
00898     double lenslet_y_halfpix = lenslet_axes[0]%2==1 ? 0 : .5;
00899     int lenslet_x_extrapix = lenslet_axes[1]%2==1 ? 1 : 0;
00900     int lenslet_y_extrapix = lenslet_axes[0]%2==1 ? 1 : 0;
00901 
00902     // The deformable mirror halfpixel information
00903     vector<long> dm_axes = ideal_dm.get_axes();
00904     double dm_x_halfpix = dm_axes[1]%2==1 ? 0 : .5;
00905     double dm_y_halfpix = dm_axes[0]%2==1 ? 0 : .5;
00906     int dm_x_extrapix = dm_axes[1]%2==1 ? 1 : 0;
00907     int dm_y_extrapix = dm_axes[0]%2==1 ? 1 : 0;
00908 
00909     long nlenslets = lenslet_axes[0]*lenslet_axes[1];
00910     long nactuators = dm_axes[0]*dm_axes[1];
00911 
00912 
00914     // Construct the geometry matrix //
00916 
00917     vector<long> geometry_matrix_axes(2,2*nlenslets);
00918     geometry_matrix_axes[1] = nactuators;
00919 
00920     T * geometry_matrix_data;
00921 
00922     try{
00923       int nelem = geometry_matrix_axes[0]*geometry_matrix_axes[1];
00924       geometry_matrix_data = new T[nelem];
00925       for(int i=0; i<nelem; i++)
00926         geometry_matrix_data[i] = 0;
00927     } catch(...){
00928       cerr << "arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor error - "
00929            << "unable to allocate memory for a geometry matrix with " 
00930            << geometry_matrix_axes[0]*geometry_matrix_axes[1] << " elements\n";
00931       throw(string("arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor"));
00932     }
00933 
00934     three_point subaperture_center_point;
00935     three_vector subap_corner_offset_a = .5*(lenslet_dy+lenslet_dx);
00936     three_vector subap_corner_offset_b = .5*(lenslet_dy-lenslet_dx);
00937     three_vector actuator_offset_a = dm_dy+dm_dx;
00938     three_vector actuator_offset_b = dm_dy-dm_dx;
00939 
00940     vector<three_point> subaperture_vertices(4);
00941     vector<three_point> actuator_influence_function_vertices(4);
00942     vector<three_point> intersection_vertices;
00943 
00944 
00945     long index;
00946     double overlap;
00947     double subaperture_area = cross_product(lenslet_dx, lenslet_dy).length();
00948     double sign_convention = aplusplus_sign_convention ? -1 : 1;
00949 
00950     three_frame local_actuator_frame, local_subap_frame;
00951     vector<long> unilluminated_subaps;
00952 
00953     double lenslet_pitch = sq_lnslt_arr.get_lenslet_pitch();
00954     double norm = 1/(lenslet_pitch*lenslet_pitch*lenslet_pitch);
00955 
00956     // These are the geometric relationships between the dm and lenslet coordinates
00957     double a_0 = dot_product(ideal_dm.x(), sq_lnslt_arr.x());
00958     double a_1 = dot_product(ideal_dm.x(), sq_lnslt_arr.y());
00959     double b_0 = dot_product(ideal_dm.y(), sq_lnslt_arr.x());
00960     double b_1 = dot_product(ideal_dm.y(), sq_lnslt_arr.y());
00961     double a_2, b_2;
00962 
00963     // These hold the integrals over the polygon
00964     double S_0, S_x, S_y;
00965 
00966     // Signs for the 4 pyramid faces
00967     double s_u, s_v;
00968 
00969     try{
00970       // loop over subaps
00971       for(int l=-lenslet_axes[1]/2; l<lenslet_axes[1]/2+lenslet_x_extrapix; l++){
00972         for(int m=-lenslet_axes[0]/2; m<lenslet_axes[0]/2+lenslet_y_extrapix; m++){
00973           
00974           subaperture_center_point = ap + 
00975             (lenslet_array_origin_offset + (l+lenslet_x_halfpix)*lenslet_dx + (m+lenslet_y_halfpix)*lenslet_dy);
00976 
00977           subaperture_vertices[0] = subaperture_center_point + subap_corner_offset_a;
00978           subaperture_vertices[1] = subaperture_center_point + subap_corner_offset_b;
00979           subaperture_vertices[2] = subaperture_center_point - subap_corner_offset_a;
00980           subaperture_vertices[3] = subaperture_center_point - subap_corner_offset_b;
00981 
00982           /*
00983           subaperture_vertices[0] = subaperture_center_point + subap_corner_offset_a;
00984           subaperture_vertices[1] = subaperture_center_point - subap_corner_offset_b;
00985           subaperture_vertices[2] = subaperture_center_point - subap_corner_offset_a;
00986           subaperture_vertices[3] = subaperture_center_point + subap_corner_offset_b;
00987           */
00988 
00989           overlap = ap.convex_polygon_overlap(subaperture_vertices);
00990 
00991           if(overlap<subaperture_area*subaperture_illumination_threshold){
00992             unilluminated_subaps.push_back((l+lenslet_axes[1]/2)*lenslet_axes[0]+m+lenslet_axes[0]/2);
00993             continue;
00994           }
00995 
00996           local_subap_frame = sq_lnslt_arr;
00997           local_subap_frame.three_point::operator=(subaperture_vertices[2]);
00998 
00999           // loop over actuators
01000           for(int i=-dm_axes[1]/2; i<dm_axes[1]/2+dm_x_extrapix; i++){
01001             for(int j=-dm_axes[0]/2; j<dm_axes[0]/2+dm_y_extrapix; j++){
01002               
01003               // one pyramid vertex is always coincident with the actuator location
01004               actuator_influence_function_vertices[0] = ap + 
01005                 (dm_origin_offset + (i+dm_x_halfpix)*dm_dx + (j+dm_y_halfpix)*dm_dy);
01006         
01007               if((actuator_influence_function_vertices[0]-subaperture_center_point).length_squared()>geometry_matrix_buffer)
01008                 continue;
01009               
01010               // loop over facets of the pyramid
01011               for(int k=0; k<4; k++){
01012                   
01013                 if(k==0){
01014                   actuator_influence_function_vertices[1] = actuator_influence_function_vertices[0] + dm_dx;
01015                   actuator_influence_function_vertices[2] = actuator_influence_function_vertices[1] + dm_dy;
01016                   actuator_influence_function_vertices[3] = actuator_influence_function_vertices[2] - dm_dx;
01017                   s_u = s_v = -1;
01018                 } else if(k==1){
01019                   actuator_influence_function_vertices[1] = actuator_influence_function_vertices[0] + dm_dy;
01020                   actuator_influence_function_vertices[2] = actuator_influence_function_vertices[1] - dm_dx;
01021                   actuator_influence_function_vertices[3] = actuator_influence_function_vertices[2] - dm_dy;
01022                   s_u = 1; s_v = -1;
01023                 } else if(k==2){
01024                   actuator_influence_function_vertices[1] = actuator_influence_function_vertices[0] - dm_dx;
01025                   actuator_influence_function_vertices[2] = actuator_influence_function_vertices[1] - dm_dy;
01026                   actuator_influence_function_vertices[3] = actuator_influence_function_vertices[2] + dm_dx;
01027                   s_u = s_v = 1;
01028                 } else if(k==3){
01029                   actuator_influence_function_vertices[1] = actuator_influence_function_vertices[0] - dm_dy;
01030                   actuator_influence_function_vertices[2] = actuator_influence_function_vertices[1] + dm_dx;
01031                   actuator_influence_function_vertices[3] = actuator_influence_function_vertices[2] + dm_dy;
01032                   s_u = -1; s_v = 1;
01033                 }
01034 
01035                 intersection_vertices = 
01036                   get_convex_polygon_intersection(actuator_influence_function_vertices, subaperture_vertices);
01037 
01038                 overlap = 0;
01039                 if(intersection_vertices.size()>2){
01040                   try{overlap = ap.convex_polygon_overlap(intersection_vertices);}
01041                   catch(...) {
01042                     cerr << "facet " << k << endl;
01043                     for(int i=0; i<actuator_influence_function_vertices.size(); i++)
01044                       actuator_influence_function_vertices[i].print(cerr, "aif ");
01045                     cerr << endl;
01046                     for(int i=0; i<subaperture_vertices.size(); i++)
01047                       subaperture_vertices[i].print(cerr, "subap ");
01048                     cerr << endl;
01049                     for(int i=0; i<intersection_vertices.size(); i++)
01050                       intersection_vertices[i].print(cerr, "int ");
01051                     cerr << endl;
01052                     throw(string("overlap"));
01053                   }
01054                 }
01055 
01056                 if(overlap>0){
01057                   index = ((i+dm_axes[1]/2)*dm_axes[0]+j+dm_axes[0]/2)*2*nlenslets + 
01058                     (l+lenslet_axes[1]/2)*lenslet_axes[0]+m+lenslet_axes[0]/2;
01059 
01060 
01061                   local_actuator_frame = three_frame(ideal_dm);
01062                   local_actuator_frame.three_point::operator=(actuator_influence_function_vertices[0]);
01063                   a_2 = local_subap_frame.three_point::x(local_actuator_frame);
01064                   b_2 = local_subap_frame.three_point::y(local_actuator_frame);
01065 
01066                   S_0 = get_area_of_polygon(intersection_vertices);
01067 
01068                   /*
01069                   if(l==0 && m==0)
01070                     convex_polygon_integration(local_subap_frame,
01071                                                intersection_vertices,
01072                                                S_x, 
01073                                                S_y,1);
01074                   else
01075                   */
01076                   convex_polygon_integration(local_subap_frame,
01077                                              intersection_vertices,
01078                                              S_x, 
01079                                              S_y);
01080 
01081                   geometry_matrix_data[index] += 
01082                     -1*sign_convention*norm*((s_u*a_0*(lenslet_pitch+s_v*b_2)+s_v*b_0*(lenslet_pitch+s_u*a_2))*S_0 +
01083                                              2*s_u*s_v*a_0*b_0*S_x + s_u*s_v*(a_0*b_1+a_1*b_0)*S_y);
01084                   
01085                   geometry_matrix_data[index+nlenslets] += 
01086                     -1*norm*((s_u*a_1*(lenslet_pitch+s_v*b_2)+s_v*b_1*(lenslet_pitch+s_u*a_2))*S_0 +
01087                              s_u*s_v*(a_0*b_1+a_1*b_0)*S_x + 2*s_u*s_v*a_1*b_1*S_y);
01088                   /*
01089                   if(l==0 && m==0){
01090                     cerr << i << "\t" << j << "\t" << k << endl;
01091                     
01092                     cerr << "a0 " << a_0 << "\tb0 " << b_0 << endl;
01093                     cerr << "a1 " << a_1 << "\tb1 " << b_1 << endl;
01094                     cerr << "a2 " << a_2/lenslet_pitch << "\tb2 " << b_2/lenslet_pitch << endl;
01095                     cerr << "su " << s_u << " sv " << s_v << endl;
01096                     
01097                     cerr << "S0 " << S_0/lenslet_pitch/lenslet_pitch
01098                          << " Sx " << S_x/lenslet_pitch/lenslet_pitch/lenslet_pitch
01099                          << " Sy " << S_y/lenslet_pitch/lenslet_pitch/lenslet_pitch
01100                          << endl;
01101                     
01102                     cerr << "facet "
01103                          << norm*((s_u*a_0*(lenslet_pitch+s_v*b_2)+s_v*b_0*(lenslet_pitch+s_u*a_2))*S_0 +
01104                                   2*s_u*s_v*a_0*b_0*S_x + s_u*s_v*(a_0*b_1+a_1*b_0)*S_y)
01105                          << "\t" 
01106                          << norm*((s_u*a_1*(lenslet_pitch+s_v*b_2)+s_v*b_1*(lenslet_pitch+s_u*a_2))*S_0 +
01107                                   s_u*s_v*(a_0*b_1+a_1*b_0)*S_x + 2*s_u*s_v*a_1*b_1*S_y)
01108                          << endl;
01109                     
01110                     cerr << "geo " << geometry_matrix_data[index] << "\t" 
01111                     << geometry_matrix_data[index+nlenslets] << endl << endl << endl;
01112                   }
01113                   */
01114                 }
01115               }
01116             }
01117           }
01118         }
01119       }
01120     } catch(...){
01121       cerr << "arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor error - "
01122            << "could not form geometry matrix\n";
01123       throw(string("arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor"));
01124     }
01125 
01126     // Warning - the svd appears to overwrite the input array.  Here we make the copy
01127     // to preserve the geometry matrix, if this has been requested
01128     if(store_geometry_matrix)
01129       geometry_matrix = pixel_array<T>(geometry_matrix_axes, geometry_matrix_data);
01130 
01131 
01132 
01133 
01135     // Perform the SVD //
01137     
01138     char jobu[1];
01139     char jobvt[1];
01140     if(store_eigenmodes)
01141       jobu[0] = jobvt[0] = 'A';
01142     else 
01143       jobu[0] = jobvt[0] = 'S';
01144     int lwork=-1, info;
01145     T optimal_workspace_size;
01146     T *singular_values, *g_gtranspose_eigenmode_data, *gtranspose_g_eigenmode_data, *work;
01147 
01148     int geo_mtx_axes_0 = geometry_matrix_axes[0];
01149     int geo_mtx_axes_1 = geometry_matrix_axes[1];
01150 
01151     singular_value_decomposition<T>(jobu, 
01152                                     jobvt, 
01153                                     geo_mtx_axes_0,
01154                                     geo_mtx_axes_1, 
01155                                     geometry_matrix_data, 
01156                                     geo_mtx_axes_0, 
01157                                     singular_values, 
01158                                     g_gtranspose_eigenmode_data, 
01159                                     geo_mtx_axes_0, 
01160                                     gtranspose_g_eigenmode_data, 
01161                                     geo_mtx_axes_1,
01162                                     &optimal_workspace_size, 
01163                                     lwork, 
01164                                     info);
01165     
01166     lwork = (int)optimal_workspace_size;
01167 
01168     try{
01169       singular_values = new T[geometry_matrix_axes[1]];
01170       if(store_eigenmodes)
01171         g_gtranspose_eigenmode_data = new T[geometry_matrix_axes[0]*geometry_matrix_axes[0]];
01172       else
01173         g_gtranspose_eigenmode_data = new T[geometry_matrix_axes[0]*geometry_matrix_axes[1]];
01174       gtranspose_g_eigenmode_data = new T[geometry_matrix_axes[1]*geometry_matrix_axes[1]];
01175       work = new T[(int)(optimal_workspace_size)];
01176     } catch(...) {
01177       cerr << "arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor error - "
01178            << "unable to allocate memory to perform the singular value decomposition\n";
01179       throw(string("arroyo_least_squares_reconstructor::arroyo_least_squares_reconstructor"));
01180     }
01181 
01182     singular_value_decomposition<T>(jobu, 
01183                                     jobvt, 
01184                                     geo_mtx_axes_0, 
01185                                     geo_mtx_axes_1, 
01186                                     geometry_matrix_data, 
01187                                     geo_mtx_axes_0, 
01188                                     singular_values, 
01189                                     g_gtranspose_eigenmode_data, 
01190                                     geo_mtx_axes_0, 
01191                                     gtranspose_g_eigenmode_data, 
01192                                     geo_mtx_axes_1,
01193                                     work, 
01194                                     lwork, 
01195                                     info);
01196     
01197     delete [] work;
01198     delete [] geometry_matrix_data;
01199 
01200 
01201     // Here we add the number of projected modes to the short axis to
01202     // allow room in the reconstructor matrix for modal reconstruction
01203     // from the centroids
01204     vector<long> reconstructor_axes(geometry_matrix_axes);
01205     reconstructor_axes[1] += projected_modes.get_axes()[0];
01206     this->pixel_array<T>::set_axes(reconstructor_axes); 
01207 
01208     // The eigenvalues are sorted in descending order.  We only process
01209     // entries for which the eigenvalues are above the threshold
01210     int limit = 0;
01211     double scaled_singular_value_threshold = 
01212       sqrt(eigenvalue_threshold*singular_values[0]*singular_values[0]);
01213     while(limit<geometry_matrix_axes[1] && 
01214           singular_values[limit]>scaled_singular_value_threshold) 
01215       limit++;
01216 
01217     int indexa;
01218     double tmp;
01219     // Form the pseudoinverse from V S^{+} U^{T}
01220     for(int i=0; i<geometry_matrix_axes[1]; i++){
01221       for(int j=0; j<geometry_matrix_axes[0]; j++){
01222         tmp = 0;
01223         indexa = i*geometry_matrix_axes[1];
01224         for(int k=0; k<limit; k++)
01225           tmp += gtranspose_g_eigenmode_data[indexa+k]*
01226             g_gtranspose_eigenmode_data[j+k*geometry_matrix_axes[0]]/singular_values[k];
01227 
01228         this->pixeldata[i*geometry_matrix_axes[0]+j]=tmp;
01229       }
01230     }
01231 
01232     if(store_eigenmodes)
01233       sqrt_eigenvalues = pixel_array<T>(vector<long>(1,geometry_matrix_axes[1]), singular_values);
01234     delete [] singular_values;
01235 
01236     if(store_eigenmodes)
01237       gtranspose_g_eigenmodes = pixel_array<T>(vector<long>(2,geometry_matrix_axes[1]), gtranspose_g_eigenmode_data);
01238     delete [] gtranspose_g_eigenmode_data;
01239 
01240     if(store_eigenmodes)
01241       g_gtranspose_eigenmodes = pixel_array<T>(vector<long>(2,geometry_matrix_axes[0]), g_gtranspose_eigenmode_data);
01242     delete [] g_gtranspose_eigenmode_data;
01243 
01244 
01246     // Zero columns in the reconstructor     //
01247     // corresponding to unilluminated subaps //
01249     /*
01250     for(int i=0; i<unilluminated_subaps.size(); i++){
01251       for(int j=0; j<reconstructor_axes[1]; j++){
01252         this->pixeldata[geometry_matrix_axes[0]*j + unilluminated_subaps[i]] = 0;
01253         //this->pixeldata[geometry_matrix_axes[1]*unilluminated_subaps[i]+nlenslets] = 0;
01254       }
01255     }
01256     */
01257 
01258 
01259 
01260 
01262     // Perform the modal projection //
01264 
01265     if(projected_modes.get_order()>0){
01266 
01267       int array_index = 2*nactuators*nlenslets; 
01268       // Skip piston
01269       array_index+=2*nlenslets;
01270 
01271       int nunilluminated_subaps = unilluminated_subaps.size();
01272       int subap_index;
01273 
01274       if(modal_projection_in_actuator_space){
01275         
01276         for(int i=0; i<nunilluminated_subaps; i++)
01277           unilluminated_subaps.push_back(unilluminated_subaps[i]+nlenslets);
01278 
01279         // Fill in rows of the reconstructor to perform x and y tilt computation
01280         subap_index = 0;
01281         for(int i=0; i<geometry_matrix_axes[0]; i++){
01282           while(i>unilluminated_subaps[subap_index] && 
01283                 subap_index<nunilluminated_subaps) 
01284             subap_index++;
01285           if(i!=unilluminated_subaps[subap_index]){
01286             for(int j=0; j<nactuators; j++){
01287               this->pixeldata[array_index+i] += 
01288                 (2*(j%dm_axes[0])/(double)dm_axes[0] - 1)*this->pixeldata[i+j*geometry_matrix_axes[0]];
01289               this->pixeldata[array_index+2*nlenslets+i] += 
01290                 (2*(j/dm_axes[0])/(double)dm_axes[0] - 1)*this->pixeldata[i+j*geometry_matrix_axes[0]]; 
01291             }
01292           }
01293         }
01294 
01295         // Project off x and y tilt from the zonal part of the reconstructor
01296         
01297 
01298         
01299       } else {
01300         
01301         double tmp, mean_fac = 1/(double)(nlenslets - unilluminated_subaps.size());
01302         
01303         if(projected_modes.get_cos_coeff(1,1)!=0){        
01304 
01305           // Project the x tilt off the zonal elements
01306           for(int i=0; i<geometry_matrix_axes[1]; i++){
01307             subap_index = 0;
01308             tmp = 0;
01309             for(int j=0; j<nlenslets; j++)
01310               tmp += this->pixeldata[i*geometry_matrix_axes[0]+j];
01311 
01312             tmp *= mean_fac;
01313 
01314             for(int j=0; j<nlenslets; j++){
01315               while(j>unilluminated_subaps[subap_index] && 
01316                     subap_index<nunilluminated_subaps) 
01317                 subap_index++;
01318               if(j!=unilluminated_subaps[subap_index])
01319                 this->pixeldata[i*geometry_matrix_axes[0]+j] -= tmp;
01320 
01321             }
01322           }
01323 
01324           // Fill in a row of the reconstructor to perform x tilt computation
01325           subap_index = 0;
01326           for(int j=0; j<nlenslets; j++){
01327             while(j>unilluminated_subaps[subap_index] && 
01328                   subap_index<nunilluminated_subaps) 
01329               subap_index++;
01330             if(j!=unilluminated_subaps[subap_index])
01331               this->pixeldata[array_index+j] = 2*mean_fac;
01332           }
01333           array_index += 2*nlenslets;
01334         }
01335 
01336         if(projected_modes.get_sin_coeff(1,1)!=0){        
01337 
01338           // Project the y tilt off the zonal elements
01339           for(int i=0; i<geometry_matrix_axes[1]; i++){
01340             subap_index = 0;
01341             tmp = 0;
01342             for(int j=nlenslets; j<geometry_matrix_axes[0]; j++)
01343               tmp += this->pixeldata[i*geometry_matrix_axes[0]+j];
01344 
01345             tmp *= mean_fac;
01346 
01347             for(int j=nlenslets; j<geometry_matrix_axes[0]; j++){
01348               while(j>(unilluminated_subaps[subap_index]+nlenslets) && 
01349                     subap_index<nunilluminated_subaps) 
01350                 subap_index++;
01351               if(j!=(unilluminated_subaps[subap_index]+nlenslets))
01352                 this->pixeldata[i*geometry_matrix_axes[0]+j] -= tmp;
01353 
01354             }
01355           }
01356 
01357           // Fill in a row of the reconstructor to perform y tilt computation
01358           subap_index = 0;
01359           for(int j=nlenslets; j<geometry_matrix_axes[0]; j++){
01360             while(j>(unilluminated_subaps[subap_index]+nlenslets) && 
01361                   subap_index<nunilluminated_subaps) 
01362               subap_index++;
01363             if(j!=(unilluminated_subaps[subap_index]+nlenslets))
01364               this->pixeldata[array_index+j] = 2*mean_fac;
01365           }
01366           array_index += 2*nlenslets;
01367         }
01368       }
01369     }
01370   }
01371 }
01372 
01373 #endif

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