LCOV - code coverage report
Current view: top level - apps/dmPokeXCorr - dmPokeXCorr.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 0.0 % 107 0
Test Date: 2026-01-03 21:03:39 Functions: 0.0 % 17 0

            Line data    Source code
       1              : /** \file dmPokeXCorr.hpp
       2              :  * \brief The MagAO-X DM Poke Centering header file
       3              :  *
       4              :  * \ingroup dmPokeXCorr_files
       5              :  */
       6              : 
       7              : #ifndef dmPokeXCorr_hpp
       8              : #define dmPokeXCorr_hpp
       9              : 
      10              : #include <mx/improc/imageFilters.hpp>
      11              : #include <mx/improc/imageXCorrFFT.hpp>
      12              : using namespace mx::improc;
      13              : 
      14              : #include <mx/math/fit/fitGaussian.hpp>
      15              : 
      16              : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
      17              : #include "../../magaox_git_version.h"
      18              : 
      19              : /** \defgroup dmPokeXCorr
      20              :  * \brief The MagAO-X application to center a DM pupil by poking actuators
      21              :  *
      22              :  * <a href="../handbook/operating/software/apps/dmPokeXCorr.html">Application Documentation</a>
      23              :  *
      24              :  * \ingroup apps
      25              :  *
      26              :  */
      27              : 
      28              : /** \defgroup dmPokeXCorr_files
      29              :  * \ingroup dmPokeXCorr
      30              :  */
      31              : 
      32              : namespace MagAOX
      33              : {
      34              : namespace app
      35              : {
      36              : 
      37              : struct zrespShmimT
      38              : {
      39            0 :     static std::string configSection()
      40              :     {
      41            0 :         return "zrespM";
      42              :     };
      43            0 :     static std::string indiPrefix()
      44              :     {
      45            0 :         return "zrespM";
      46              :     };
      47              : };
      48              : 
      49              : /// The MagAO-X DM to PWFS alignment Application
      50              : /**
      51              :  * \ingroup dmPokeXCorr
      52              :  */
      53              : class dmPokeXCorr : public MagAOXApp<true>,
      54              :                     public dev::dmPokeWFS<dmPokeXCorr>,
      55              :                     public dev::shmimMonitor<dmPokeXCorr, dev::dmPokeWFS<dmPokeXCorr>::wfsShmimT>,
      56              :                     public dev::shmimMonitor<dmPokeXCorr, dev::dmPokeWFS<dmPokeXCorr>::darkShmimT>,
      57              :                     public dev::shmimMonitor<dmPokeXCorr, zrespShmimT>,
      58              :                     public dev::telemeter<dmPokeXCorr>
      59              : {
      60              :     // Give the test harness access.
      61              :     friend class dmPokeXCorr_test;
      62              : 
      63              :     friend class dev::dmPokeWFS<dmPokeXCorr>;
      64              : 
      65              :     typedef dev::dmPokeWFS<dmPokeXCorr> dmPokeWFST;
      66              : 
      67              :     friend class dev::shmimMonitor<dmPokeXCorr, dev::dmPokeWFS<dmPokeXCorr>::wfsShmimT>;
      68              : 
      69              :     typedef dev::shmimMonitor<dmPokeXCorr, dev::dmPokeWFS<dmPokeXCorr>::wfsShmimT> shmimMonitorT;
      70              : 
      71              :     friend class dev::shmimMonitor<dmPokeXCorr, dev::dmPokeWFS<dmPokeXCorr>::darkShmimT>;
      72              : 
      73              :     typedef dev::shmimMonitor<dmPokeXCorr, dev::dmPokeWFS<dmPokeXCorr>::darkShmimT> darkShmimMonitorT;
      74              : 
      75              :     friend class dev::shmimMonitor<dmPokeXCorr, zrespShmimT>;
      76              : 
      77              :     typedef dev::shmimMonitor<dmPokeXCorr, zrespShmimT> zrespShmimMonitorT;
      78              : 
      79              :     friend class dev::telemeter<dmPokeXCorr>;
      80              : 
      81              :     typedef dev::telemeter<dmPokeXCorr> telemeterT;
      82              : 
      83              :   protected:
      84              :     /** \name Configurable Parameters
      85              :      *@{
      86              :      */
      87              : 
      88              :     std::string m_zRespMFile;
      89              : 
      90              :     ///@}
      91              : 
      92              :     mx::improc::imageXCorrFFT<eigenImage<float>> m_xcorr;
      93              : 
      94              :     mx::improc::milkImage<float> m_refIm;
      95              : 
      96              :   public:
      97              :     /// Default c'tor.
      98              :     dmPokeXCorr();
      99              : 
     100              :     /// D'tor, declared and defined for noexcept.
     101            0 :     ~dmPokeXCorr() noexcept
     102            0 :     {
     103            0 :     }
     104              : 
     105              :     /**\name MagAOX Interface
     106              :      *
     107              :      * @{
     108              :      */
     109              :     virtual void setupConfig();
     110              : 
     111              :     /// Implementation of loadConfig logic, separated for testing.
     112              :     /** This is called by loadConfig().
     113              :      */
     114              :     int loadConfigImpl(
     115              :         mx::app::appConfigurator &_config /**< [in] an application configuration from which to load values*/ );
     116              : 
     117              :     virtual void loadConfig();
     118              : 
     119              :     /// Startup function
     120              :     /**
     121              :      *
     122              :      */
     123              :     virtual int appStartup();
     124              : 
     125              :     /// Implementation of the FSM for dmPokeXCorr.
     126              :     /**
     127              :      * \returns 0 on no critical error
     128              :      * \returns -1 on an error requiring shutdown
     129              :      */
     130              :     virtual int appLogic();
     131              : 
     132              :     /// Shutdown the app.
     133              :     /**
     134              :      *
     135              :      */
     136              :     virtual int appShutdown();
     137              : 
     138              :     ///@}
     139              : 
     140            0 :     shmimMonitorT &shmimMonitor()
     141              :     {
     142            0 :         return *dynamic_cast<shmimMonitorT *>( this );
     143              :     }
     144              : 
     145            0 :     darkShmimMonitorT &darkShmimMonitor()
     146              :     {
     147            0 :         return *static_cast<darkShmimMonitorT *>( this );
     148              :     }
     149              : 
     150              :     /** \name zrespShmimMonitorT inteface
     151              :      * @{
     152              :      */
     153              : 
     154              :     int allocate( const zrespShmimT &dummy );
     155              : 
     156              :     int processImage( void *curr_src, const zrespShmimT &dummy );
     157              : 
     158              :     using dmPokeWFST::allocate;
     159              : 
     160              :     using dmPokeWFST::processImage;
     161              : 
     162              :     ///@}
     163              : 
     164              :     /** \name dmPokeWFS Interface
     165              :      * @{
     166              :      */
     167              : 
     168              :     /// Run the sensor steps
     169              :     /** Coordinates the actions of poking and collecting images.
     170              :      * Upon completion this calls runSensor.  If \p firstRun == true, one time
     171              :      * actions such as taking a dark can be executed.
     172              :      *
     173              :      * \returns 0 on success
     174              :      * \returns \< 0 on an error
     175              :      */
     176              :     int runSensor( bool firstRun /**< [in] flag indicating this is the first call.  triggers taking a dark if true.*/ );
     177              : 
     178              :     /// Analyze the poke image
     179              :     /** This analyzes the resulting poke image and reports the results.
     180              :      *
     181              :      * \returns 0 on success
     182              :      * \returns \< 0 on an error
     183              :      */
     184              :     int analyzeSensor();
     185              : 
     186              :     ///@}
     187              : 
     188              :     /** \name INDI Interface
     189              :      * @{
     190              :      */
     191              :   protected:
     192              :     ///@}
     193              : 
     194              :     /** \name Telemeter Interface
     195              :      *
     196              :      * @{
     197              :      */
     198              :     int checkRecordTimes();
     199              : 
     200              :     ///@}
     201              : };
     202              : 
     203            0 : dmPokeXCorr::dmPokeXCorr() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
     204              : {
     205            0 :     darkShmimMonitorT::m_getExistingFirst  = true;
     206            0 :     zrespShmimMonitorT::m_getExistingFirst = true;
     207              : 
     208            0 :     return;
     209            0 : }
     210              : 
     211            0 : void dmPokeXCorr::setupConfig()
     212              : {
     213            0 :     DMPOKEWFS_SETUP_CONFIG( config );
     214              : 
     215            0 :     SHMIMMONITORT_SETUP_CONFIG( zrespShmimMonitorT, config );
     216              : 
     217            0 :     TELEMETER_SETUP_CONFIG( config );
     218              : }
     219              : 
     220            0 : int dmPokeXCorr::loadConfigImpl( mx::app::appConfigurator &_config )
     221              : {
     222            0 :     DMPOKEWFS_LOAD_CONFIG( _config );
     223              : 
     224            0 :     SHMIMMONITORT_LOAD_CONFIG( zrespShmimMonitorT, _config );
     225              : 
     226            0 :     TELEMETER_LOAD_CONFIG( _config );
     227              : 
     228            0 :     return 0;
     229              : }
     230              : 
     231            0 : void dmPokeXCorr::loadConfig()
     232              : {
     233            0 :     if( loadConfigImpl( config ) < 0 )
     234              :     {
     235            0 :         m_shutdown = true;
     236              :     }
     237            0 : }
     238              : 
     239            0 : int dmPokeXCorr::appStartup()
     240              : {
     241            0 :     DMPOKEWFS_APP_STARTUP;
     242              : 
     243            0 :     SHMIMMONITORT_APP_STARTUP( zrespShmimMonitorT );
     244              : 
     245            0 :     TELEMETER_APP_STARTUP;
     246              : 
     247              :     // Gotta connect to the DM stream to find out its size
     248            0 :     mx::improc::milkImage<float> mdm;
     249              :     try
     250              :     {
     251            0 :         mdm.open( m_dmChan );
     252              :     }
     253            0 :     catch( const std::exception &e ) // this can check for invalid_argument and distinguish not existing
     254              :     {
     255            0 :         return log<software_error, -1>( { __FILE__, __LINE__, std::string( "exception opening DM: " ) + e.what() } );
     256            0 :     }
     257              : 
     258            0 :     state( stateCodes::READY );
     259              : 
     260            0 :     return 0;
     261            0 : }
     262              : 
     263            0 : int dmPokeXCorr::appLogic()
     264              : {
     265            0 :     DMPOKEWFS_APP_LOGIC;
     266              : 
     267            0 :     SHMIMMONITORT_APP_LOGIC( zrespShmimMonitorT );
     268            0 :     SHMIMMONITORT_UPDATE_INDI( zrespShmimMonitorT );
     269            0 :     SHMIMMONITORT_UPDATE_INDI( shmimMonitorT );
     270            0 :     SHMIMMONITORT_UPDATE_INDI( darkShmimMonitorT );
     271              : 
     272            0 :     TELEMETER_APP_LOGIC;
     273              : 
     274            0 :     return 0;
     275              : }
     276              : 
     277            0 : int dmPokeXCorr::appShutdown()
     278              : {
     279            0 :     DMPOKEWFS_APP_SHUTDOWN;
     280              : 
     281            0 :     SHMIMMONITORT_APP_SHUTDOWN( zrespShmimMonitorT );
     282              : 
     283            0 :     TELEMETER_APP_SHUTDOWN;
     284              : 
     285            0 :     return 0;
     286              : }
     287              : 
     288            0 : int dmPokeXCorr::allocate( const zrespShmimT &dummy )
     289              : {
     290              :     static_cast<void>( dummy );
     291              : 
     292            0 :     if( m_refIm.rows() != zrespShmimMonitorT::m_width || m_refIm.cols() != zrespShmimMonitorT::m_height )
     293              :     {
     294            0 :         m_refIm.create( m_configName + "_refIm", zrespShmimMonitorT::m_width, zrespShmimMonitorT::m_height );
     295              :     }
     296              : 
     297            0 :     return 0;
     298              : }
     299              : 
     300            0 : int dmPokeXCorr::processImage( void *curr_src, const zrespShmimT &dummy )
     301              : {
     302              :     static_cast<void>( dummy );
     303              : 
     304              :     // Gotta connect to the DM stream to find out its size
     305              :     // can't assume that we have connected anywhere else.
     306            0 :     mx::improc::milkImage<float> mdm;
     307              :     try
     308              :     {
     309            0 :         mdm.open( m_dmChan );
     310              :     }
     311            0 :     catch( const std::exception &e )
     312              :     {
     313            0 :         return log<software_error, -1>( { __FILE__, __LINE__, std::string( "exception opening DM: " ) + e.what() } );
     314            0 :     }
     315              : 
     316              :     mx::improc::eigenCube<float> zRespM(
     317            0 :         (float *)curr_src, zrespShmimMonitorT::m_width, zrespShmimMonitorT::m_height, zrespShmimMonitorT::m_depth );
     318              : 
     319            0 :     mx::improc::eigenImage<float> refIm;
     320            0 :     refIm.resize( zRespM.rows(), zRespM.cols() );
     321            0 :     refIm.setZero();
     322              : 
     323            0 :     for( size_t n = 0; n < m_poke_x.size(); ++n )
     324              :     {
     325            0 :         int actno = m_poke_y[n] * mdm.rows() + m_poke_x[n];
     326              : 
     327            0 :         refIm += zRespM.image( actno );
     328              :     }
     329              : 
     330            0 :     m_refIm = refIm;
     331              : 
     332            0 :     std::cerr << "Got reference: " << refIm.rows() << " x " << refIm.cols() << '\n';
     333              :     try
     334              :     {
     335            0 :         m_xcorr.peakMethod( xcorrPeakMethod::mftOversamp );
     336            0 :         m_xcorr.normalize( true );
     337            0 :         m_xcorr.maxLag( 10 );
     338            0 :         m_xcorr.tol( 0.001 );
     339              : 
     340            0 :         m_xcorr.refIm( refIm, 1 );
     341              : 
     342              :     }
     343            0 :     catch( const std::exception &e )
     344              :     {
     345            0 :         return log<software_error, -1>( { __FILE__, __LINE__, std::string( "exception caught: \n" ) + e.what() } );
     346            0 :     }
     347            0 :     return 0;
     348            0 : }
     349              : 
     350            0 : int dmPokeXCorr::runSensor( bool firstRun )
     351              : {
     352              :     static_cast<void>( firstRun );
     353              : 
     354            0 :     int rv = dmPokeWFST::basicRunSensor();
     355              : 
     356            0 :     if( rv > 0 )
     357              :     {
     358            0 :         return 0;
     359              :     }
     360            0 :     else if( rv < 0 )
     361              :     {
     362            0 :         log<software_error>( { __FILE__, __LINE__ } );
     363            0 :         return rv;
     364              :     }
     365              : 
     366            0 :     return 0;
     367              : }
     368              : 
     369            0 : int dmPokeXCorr::analyzeSensor()
     370              : {
     371            0 :     if( m_xcorr.refIm().rows() != m_pokeImage().rows() || m_xcorr.refIm().cols() != m_pokeImage().cols() )
     372              :     {
     373            0 :         std::cerr << "refIm:  " << m_xcorr.refIm().rows() << " x " << m_xcorr.refIm().cols() << '\n';
     374            0 :         std::cerr << "pokeIm: " << m_pokeImage().rows() << " x " << m_pokeImage().cols() << '\n';
     375            0 :         return log<software_error, -1>( { __FILE__, __LINE__, "reference is not valid" } );
     376              :     }
     377              : 
     378              :     float xs, ys, pk;
     379              : 
     380              :     try
     381              :     {
     382            0 :         m_xcorr( xs, ys, pk, m_pokeImage() );
     383              :     }
     384            0 :     catch( const std::exception &e )
     385              :     {
     386            0 :         return log<software_error, -1>( { __FILE__, __LINE__, std::string( "exception caught: \n" ) + e.what() } );
     387            0 :     }
     388              : 
     389            0 :     std::cerr.precision( 5 );
     390            0 :     std::cerr << "dmPokeXCorr::analyzeSensor: " << xs << " " << ys << "\n";
     391              : 
     392            0 :     if( updateMeasurement( xs, ys ) < 0 )
     393              :     {
     394            0 :         return log<software_error, -1>( { __FILE__, __LINE__, "error from dmPokeWFS::updateMeasurement" } );
     395              :     }
     396              : 
     397            0 :     return 0;
     398              : }
     399              : 
     400            0 : int dmPokeXCorr::checkRecordTimes()
     401              : {
     402            0 :     return telemeterT::checkRecordTimes( telem_pokeloop() );
     403              : }
     404              : 
     405              : } // namespace app
     406              : } // namespace MagAOX
     407              : 
     408              : #endif // dmPokeXCorr_hpp
        

Generated by: LCOV version 2.0-1