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

            Line data    Source code
       1              : /** \file modalGainOpt.hpp
       2              :  * \brief The MagAO-X PSD-based gain optimizer header file
       3              :  *
       4              :  * \ingroup modalGainOpt_files
       5              :  */
       6              : 
       7              : #ifndef modalGainOpt_hpp
       8              : #define modalGainOpt_hpp
       9              : 
      10              : #include <mx/mxException.hpp>
      11              : #include <mx/ao/analysis/clGainOpt.hpp>
      12              : #include <mx/ao/analysis/clAOLinearPredictor.hpp>
      13              : 
      14              : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
      15              : #include "../../magaox_git_version.h"
      16              : 
      17              : /** \defgroup modalGainOpt
      18              :  * \brief The MagAO-X application to perform PSD-based gain optimization
      19              :  *
      20              :  * <a href="../handbook/operating/software/apps/modalGainOpt.html">Application Documentation</a>
      21              :  *
      22              :  * \ingroup apps
      23              :  *
      24              :  */
      25              : 
      26              : /** \defgroup modalGainOpt_files
      27              :  * \ingroup modalGainOpt
      28              :  */
      29              : 
      30              : namespace MagAOX
      31              : {
      32              : namespace app
      33              : {
      34              : 
      35              : #define MGO_BREADCRUMB
      36              : 
      37              : // #define MGO_BREADCRUMB  std::cerr << __FILE__ << ' ' << __LINE__ << '\n';
      38              : 
      39              : struct psdShmimT
      40              : {
      41            0 :     static std::string configSection()
      42              :     {
      43            0 :         return "psdShmim";
      44              :     };
      45              : 
      46            0 :     static std::string indiPrefix()
      47              :     {
      48            0 :         return "psd";
      49              :     };
      50              : };
      51              : 
      52              : struct freqShmimT
      53              : {
      54            0 :     static std::string configSection()
      55              :     {
      56            0 :         return "freqShmim";
      57              :     };
      58              : 
      59            0 :     static std::string indiPrefix()
      60              :     {
      61            0 :         return "freq";
      62              :     };
      63              : };
      64              : 
      65              : struct gainFactShmimT
      66              : {
      67            0 :     static std::string configSection()
      68              :     {
      69            0 :         return "gainFactShmim";
      70              :     };
      71              : 
      72            0 :     static std::string indiPrefix()
      73              :     {
      74            0 :         return "gainFact";
      75              :     };
      76              : };
      77              : 
      78              : struct multFactShmimT
      79              : {
      80            0 :     static std::string configSection()
      81              :     {
      82            0 :         return "multFactShmim";
      83              :     };
      84              : 
      85            0 :     static std::string indiPrefix()
      86              :     {
      87            0 :         return "multFact";
      88              :     };
      89              : };
      90              : 
      91              : struct pcGainFactShmimT
      92              : {
      93            0 :     static std::string configSection()
      94              :     {
      95            0 :         return "pcGainFactShmim";
      96              :     };
      97              : 
      98            0 :     static std::string indiPrefix()
      99              :     {
     100            0 :         return "pcGainFact";
     101              :     };
     102              : };
     103              : 
     104              : struct pcMultFactShmimT
     105              : {
     106            0 :     static std::string configSection()
     107              :     {
     108            0 :         return "pcMultFactShmim";
     109              :     };
     110              : 
     111            0 :     static std::string indiPrefix()
     112              :     {
     113            0 :         return "pcMultFact";
     114              :     };
     115              : };
     116              : 
     117              : struct numpccoeffShmimT
     118              : {
     119            0 :     static std::string configSection()
     120              :     {
     121            0 :         return "numpccoeffShmim";
     122              :     };
     123              : 
     124            0 :     static std::string indiPrefix()
     125              :     {
     126            0 :         return "numpccoeff";
     127              :     };
     128              : };
     129              : 
     130              : struct acoeffShmimT
     131              : {
     132            0 :     static std::string configSection()
     133              :     {
     134            0 :         return "acoeffShmim";
     135              :     };
     136              : 
     137            0 :     static std::string indiPrefix()
     138              :     {
     139            0 :         return "acoeff";
     140              :     };
     141              : };
     142              : 
     143              : struct bcoeffShmimT
     144              : {
     145            0 :     static std::string configSection()
     146              :     {
     147            0 :         return "bcoeffShmim";
     148              :     };
     149              : 
     150            0 :     static std::string indiPrefix()
     151              :     {
     152            0 :         return "bcoeff";
     153              :     };
     154              : };
     155              : 
     156              : struct gainCalShmimT
     157              : {
     158            0 :     static std::string configSection()
     159              :     {
     160            0 :         return "gainCalShmim";
     161              :     };
     162              : 
     163            0 :     static std::string indiPrefix()
     164              :     {
     165            0 :         return "gainCal";
     166              :     };
     167              : };
     168              : 
     169              : struct gainCalFactShmimT
     170              : {
     171            0 :     static std::string configSection()
     172              :     {
     173            0 :         return "gainCalFactShmim";
     174              :     };
     175              : 
     176            0 :     static std::string indiPrefix()
     177              :     {
     178            0 :         return "gainCalFact";
     179              :     };
     180              : };
     181              : 
     182              : struct tauShmimT
     183              : {
     184            0 :     static std::string configSection()
     185              :     {
     186            0 :         return "tauShmim";
     187              :     };
     188              : 
     189            0 :     static std::string indiPrefix()
     190              :     {
     191            0 :         return "tau";
     192              :     };
     193              : };
     194              : 
     195              : struct noiseShmimT
     196              : {
     197            0 :     static std::string configSection()
     198              :     {
     199            0 :         return "noiseShmim";
     200              :     };
     201              : 
     202            0 :     static std::string indiPrefix()
     203              :     {
     204            0 :         return "noise";
     205              :     };
     206              : };
     207              : 
     208              : struct wfsavgShmimT
     209              : {
     210            0 :     static std::string configSection()
     211              :     {
     212            0 :         return "wfsavgShmim";
     213              :     };
     214              : 
     215            0 :     static std::string indiPrefix()
     216              :     {
     217            0 :         return "wfsavg";
     218              :     };
     219              : };
     220              : 
     221              : struct wfsmaskShmimT
     222              : {
     223            0 :     static std::string configSection()
     224              :     {
     225            0 :         return "wfsmaskShmim";
     226              :     };
     227              : 
     228            0 :     static std::string indiPrefix()
     229              :     {
     230            0 :         return "wfsmask";
     231              :     };
     232              : };
     233              : 
     234              : /// The MagAO-X PSD-based gain optimizer
     235              : /**
     236              :  * \ingroup modalGainOpt
     237              :  */
     238              : class modalGainOpt : public MagAOXApp<true>,
     239              :                      dev::shmimMonitor<modalGainOpt, psdShmimT>,
     240              :                      dev::shmimMonitor<modalGainOpt, freqShmimT>,
     241              :                      dev::shmimMonitor<modalGainOpt, gainFactShmimT>,
     242              :                      dev::shmimMonitor<modalGainOpt, multFactShmimT>,
     243              :                      dev::shmimMonitor<modalGainOpt, pcGainFactShmimT>,
     244              :                      dev::shmimMonitor<modalGainOpt, pcMultFactShmimT>,
     245              :                      dev::shmimMonitor<modalGainOpt, numpccoeffShmimT>,
     246              :                      dev::shmimMonitor<modalGainOpt, acoeffShmimT>,
     247              :                      dev::shmimMonitor<modalGainOpt, bcoeffShmimT>,
     248              :                      dev::shmimMonitor<modalGainOpt, gainCalShmimT>,
     249              :                      dev::shmimMonitor<modalGainOpt, gainCalFactShmimT>,
     250              :                      dev::shmimMonitor<modalGainOpt, tauShmimT>,
     251              :                      dev::shmimMonitor<modalGainOpt, noiseShmimT>,
     252              :                      dev::shmimMonitor<modalGainOpt, wfsavgShmimT>,
     253              :                      dev::shmimMonitor<modalGainOpt, wfsmaskShmimT>
     254              : 
     255              : {
     256              : 
     257              :     // Give the test harness access.
     258              :     friend class modalGainOpt_test;
     259              : 
     260              :     friend class dev::shmimMonitor<modalGainOpt, psdShmimT>;
     261              :     friend class dev::shmimMonitor<modalGainOpt, freqShmimT>;
     262              :     friend class dev::shmimMonitor<modalGainOpt, gainFactShmimT>;
     263              :     friend class dev::shmimMonitor<modalGainOpt, multFactShmimT>;
     264              :     friend class dev::shmimMonitor<modalGainOpt, pcGainFactShmimT>;
     265              :     friend class dev::shmimMonitor<modalGainOpt, pcMultFactShmimT>;
     266              :     friend class dev::shmimMonitor<modalGainOpt, numpccoeffShmimT>;
     267              :     friend class dev::shmimMonitor<modalGainOpt, acoeffShmimT>;
     268              :     friend class dev::shmimMonitor<modalGainOpt, bcoeffShmimT>;
     269              :     friend class dev::shmimMonitor<modalGainOpt, gainCalShmimT>;
     270              :     friend class dev::shmimMonitor<modalGainOpt, gainCalFactShmimT>;
     271              :     friend class dev::shmimMonitor<modalGainOpt, tauShmimT>;
     272              :     friend class dev::shmimMonitor<modalGainOpt, noiseShmimT>;
     273              :     friend class dev::shmimMonitor<modalGainOpt, wfsavgShmimT>;
     274              :     friend class dev::shmimMonitor<modalGainOpt, wfsmaskShmimT>;
     275              : 
     276              :   public:
     277              :     typedef dev::shmimMonitor<modalGainOpt, psdShmimT>         psdShmimMonitorT;
     278              :     typedef dev::shmimMonitor<modalGainOpt, freqShmimT>        freqShmimMonitorT;
     279              :     typedef dev::shmimMonitor<modalGainOpt, gainFactShmimT>    gainFactShmimMonitorT;
     280              :     typedef dev::shmimMonitor<modalGainOpt, multFactShmimT>    multFactShmimMonitorT;
     281              :     typedef dev::shmimMonitor<modalGainOpt, pcGainFactShmimT>  pcGainFactShmimMonitorT;
     282              :     typedef dev::shmimMonitor<modalGainOpt, pcMultFactShmimT>  pcMultFactShmimMonitorT;
     283              :     typedef dev::shmimMonitor<modalGainOpt, numpccoeffShmimT>  numpccoeffShmimMonitorT;
     284              :     typedef dev::shmimMonitor<modalGainOpt, acoeffShmimT>      acoeffShmimMonitorT;
     285              :     typedef dev::shmimMonitor<modalGainOpt, bcoeffShmimT>      bcoeffShmimMonitorT;
     286              :     typedef dev::shmimMonitor<modalGainOpt, gainCalShmimT>     gainCalShmimMonitorT;
     287              :     typedef dev::shmimMonitor<modalGainOpt, gainCalFactShmimT> gainCalFactShmimMonitorT;
     288              :     typedef dev::shmimMonitor<modalGainOpt, tauShmimT>         tauShmimMonitorT;
     289              :     typedef dev::shmimMonitor<modalGainOpt, noiseShmimT>       noiseShmimMonitorT;
     290              :     typedef dev::shmimMonitor<modalGainOpt, wfsavgShmimT>      wfsavgShmimMonitorT;
     291              :     typedef dev::shmimMonitor<modalGainOpt, wfsmaskShmimT>     wfsmaskShmimMonitorT;
     292              : 
     293              :     typedef std::chrono::time_point<std::chrono::steady_clock> timePointT;
     294              :     typedef std::chrono::duration<double>                      durationT;
     295              : 
     296              :   protected:
     297              :     /** \name Configurable Parameters
     298              :      *@{
     299              :      */
     300              : 
     301              :     int m_loopNum{ 1 }; ///< The number of the loop. Used to set shmim names, as in aolN_mgainfact.
     302              : 
     303              :     std::string m_loopName; ///< The name of the loop control INDI device name.
     304              : 
     305              :     std::string m_wfsDevice{ "camwfs" };
     306              : 
     307              :     std::string m_psdDevice{ "hopsds" }; /**< The INDI device name of the PSD calculator.  Defaults to aolN_modevalPSDs
     308              :                                    where N is m_loopNum.*/
     309              : 
     310              :     std::string m_opticalGainDevice {"strehl"};
     311              :     std::string m_opticalGainProperty {"strehl_optimal"};
     312              :     std::string m_opticalGainElement {"pyramid"};
     313              : 
     314              :     bool m_autoUpdate{ false }; ///< Flag controlling whether gains are automatically updated
     315              :     bool m_opticalGainUpdate {false}; ///< Flag controlling whether optical gain is automatically updated;
     316              : 
     317              :     float m_gainGain{ 0.1 }; ///< The gain to use for closed-loop gain updates.  Default is 0.1.
     318              : 
     319              :     uint32_t m_maxNCoeff{ 1000 };
     320              : 
     321              :     uint32_t m_defaultNCoeff{ 25 };
     322              : 
     323              :     int m_extrapOL {0}; ///< Which extrapolation method to use for the OL PSD.  0 is none.  The only other option is 1.
     324              : 
     325              :     ///@}
     326              : 
     327              :     uint32_t m_nFreq{ 0 };
     328              :     uint32_t m_nModes{ 0 };
     329              : 
     330              :     bool m_updateOnce{ false }; ///< Flag to trigger a single update with gain.
     331              : 
     332              :     bool m_dump{ false }; ///< Flag to trigger a single update with no gain.
     333              : 
     334              :     float m_fps{ 0 };
     335              : 
     336              :     /// Each mode gets its own gain optimizer
     337              :     std::vector<mx::AO::analysis::clGainOpt<float>>           m_goptCurrent;
     338              :     std::vector<mx::AO::analysis::clGainOpt<float>>           m_goptSI;
     339              :     std::vector<mx::AO::analysis::clGainOpt<float>>           m_goptLP;
     340              :     std::vector<mx::AO::analysis::clAOLinearPredictor<float>> m_linPred;
     341              : 
     342              :     bool m_goptUpdated{ true };   ///< Tracks if a parameter has updated requiring updates to the m_gopt entries.
     343              :     bool m_pcgoptUpdated{ true }; ///< Tracks if a parameter has updated requiring updates to the m_gopt entries.
     344              : 
     345              :     bool m_freqUpdated{ true }; /**< Tracks if the frequency scale has updated, which necessitates additional calcs.
     346              :                                      If true, implies m_goptUpdate == true.*/
     347              :     float m_psdTime{ 1 };
     348              :     float m_psdAvgTime{ 10 };
     349              :     float m_psdOverlapFraction{ 0.5 };
     350              : 
     351              :     std::vector<float> m_freq;
     352              : 
     353              :     mx::improc::eigenImage<float> m_clPSDs;
     354              :     mx::improc::eigenImage<float> m_clXferCurrent;
     355              :     mx::improc::eigenImage<float> m_clXferSI;
     356              :     mx::improc::eigenImage<float> m_clXferLP;
     357              : 
     358              :     std::vector<std::vector<float>> m_olPSDs;
     359              :     std::vector<std::vector<float>> m_nPSDs;
     360              : 
     361              :     std::vector<float> m_modeVarCL;
     362              :     std::vector<float> m_modeVarOL;
     363              : 
     364              :     int m_modesOn;
     365              : 
     366              :     std::vector<float> m_optGainSI;
     367              :     std::vector<float> m_gmaxSI; ///< The previously calculated maximum gains for LP
     368              :     std::vector<float> m_modeVarSI;
     369              :     std::vector<int>   m_timesOnSI;
     370              :     int   m_modesOnSI;
     371              : 
     372              :     std::vector<float> m_optGainLP;
     373              :     std::vector<float> m_gmaxLP; ///< The previously calculated maximum gains for LP
     374              :     std::vector<float> m_modeVarLP;
     375              :     std::vector<int>   m_timesOnLP;
     376              :     int m_modesOnLP;
     377              : 
     378              :     bool m_loop{ false };
     379              : 
     380              :     float m_opticalGain{ 1 };
     381              : 
     382              :     float m_opticalGainSource {1};
     383              : 
     384              :     float m_gain{ 0 };
     385              : 
     386              :     float m_mult{ 1 };
     387              : 
     388              :     float m_siGain{ 0 };
     389              : 
     390              :     float m_siMult{ 1 };
     391              : 
     392              :     bool m_doPCCalcs{ true };
     393              : 
     394              :     float m_pcGain{ 0 };
     395              : 
     396              :     float m_pcMult{ 0 };
     397              : 
     398              :     bool m_pcOn{ false };
     399              : 
     400              :     std::vector<float> m_gainFacts;
     401              : 
     402              :     std::vector<float> m_multFacts;
     403              : 
     404              :     std::vector<float> m_pcGainFacts;
     405              : 
     406              :     std::vector<float> m_pcMultFacts;
     407              : 
     408              :     std::vector<uint32_t> m_Na; // The latest user specified number of a coefficients
     409              : 
     410              :     std::vector<uint32_t> m_NaCurrent; // The current number of a coefficients
     411              : 
     412              :     std::vector<uint32_t> m_Nb; // The latest user specified number of b coefficients
     413              : 
     414              :     std::vector<uint32_t> m_NbCurrent; // The current number of b coefficients
     415              : 
     416              :     eigenImage<float> m_as;
     417              : 
     418              :     eigenImage<float> m_bs;
     419              : 
     420              :     int m_nRegCycles{ 60 }; ///< How often to regularize each mode
     421              : 
     422              :     std::vector<int> m_regCounter; ///< Counters to track when this mode was last regularized
     423              : 
     424              :     std::vector<float> m_regScale; ///< The regularization scale factors for each mode
     425              : 
     426              :     std::vector<float> m_gainCals;
     427              : 
     428              :     std::vector<float> m_gainCalFacts;
     429              : 
     430              :     std::vector<float> m_taus;
     431              : 
     432              :     eigenImage<float> m_noiseParams;
     433              : 
     434              :     eigenImage<float> m_wfsavg;
     435              :     eigenImage<float> m_wfsmask;
     436              :     float             m_counts{ 0 };
     437              :     float             m_emg{ 1 };
     438              :     int               m_npix{ 0 };
     439              : 
     440              :     int m_sinceChange{ -1 };
     441              : 
     442              :     std::string m_olPSDShmimName;
     443              :     std::string m_noisePSDShmimName;
     444              :     std::string m_clXferCurrentShmimName;
     445              :     std::string m_clXferSIShmimName;
     446              :     std::string m_clXferLPShmimName;
     447              : 
     448              :     std::string m_optGainShmimName;
     449              :     std::string m_optGainSIShmimName;
     450              :     std::string m_maxGainSIShmimName;
     451              : 
     452              :     std::string m_optGainLPShmimName;
     453              :     std::string m_maxGainLPShmimName;
     454              : 
     455              :     std::string m_modevarShmimName;
     456              : 
     457              :     IMAGE *m_olPSDStream{ nullptr };         ///< The ImageStreamIO shared memory buffer to publish the open loop PSDs
     458              :     IMAGE *m_noisePSDStream{ nullptr };      /**< The ImageStreamIO shared memory buffer to publish the noise
     459              :                                                   PSDs (single value per mode)*/
     460              :     IMAGE *m_clXferCurrentStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the SI ETF
     461              :     IMAGE *m_clXferSIStream{ nullptr };      ///< The ImageStreamIO shared memory buffer to publish the SI ETF
     462              :     IMAGE *m_clXferLPStream{ nullptr };      ///< The ImageStreamIO shared memory buffer to publish the LP ETF
     463              : 
     464              :     IMAGE *m_optGainStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the optimal gains
     465              : 
     466              :     IMAGE *m_optGainSIStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the SI optimal gains
     467              :     IMAGE *m_maxGainSIStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the SI max gains
     468              : 
     469              :     IMAGE *m_optGainLPStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the LP optimal gains
     470              :     IMAGE *m_maxGainLPStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the LP max gains
     471              : 
     472              :     IMAGE *m_modevarStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the LP optimal gains
     473              : 
     474              :   public:
     475              :     /// Default c'tor.
     476              :     modalGainOpt();
     477              : 
     478              :     /// D'tor, declared and defined for noexcept.
     479            0 :     ~modalGainOpt() noexcept
     480            0 :     {
     481            0 :     }
     482              : 
     483              :     virtual void setupConfig();
     484              : 
     485              :     /// Implementation of loadConfig logic, separated for testing.
     486              :     /** This is called by loadConfig().
     487              :      */
     488              :     int loadConfigImpl( mx::app::appConfigurator &_config /**< [in] an application configuration
     489              :                                                                     from which to load values*/ );
     490              : 
     491              :     virtual void loadConfig();
     492              : 
     493              :     /// Startup function
     494              :     /**
     495              :      *
     496              :      */
     497              :     virtual int appStartup();
     498              : 
     499              :     /// Implementation of the FSM for modalGainOpt.
     500              :     /**
     501              :      * \returns 0 on no critical error
     502              :      * \returns -1 on an error requiring shutdown
     503              :      */
     504              :     virtual int appLogic();
     505              : 
     506              :     /// Shutdown the app.
     507              :     /**
     508              :      *
     509              :      */
     510              :     virtual int appShutdown();
     511              : 
     512              :     int allocatePCShmims();
     513              : 
     514              :     int allocate( const psdShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     515              :     );
     516              : 
     517              :     int processImage( void *curr_src,   ///< [in] pointer to the start of the current frame
     518              :                       const psdShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     519              :     );
     520              : 
     521              :     int allocate( const freqShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     522              :     );
     523              : 
     524              :     int processImage( void *curr_src,    ///< [in] pointer to the start of the current frame
     525              :                       const freqShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     526              :     );
     527              : 
     528              :     int allocate( const gainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     529              :     );
     530              : 
     531              :     int processImage( void *curr_src,        ///< [in] pointer to the start of the current frame
     532              :                       const gainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     533              :     );
     534              : 
     535              :     int allocate( const multFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     536              :     );
     537              : 
     538              :     int processImage( void *curr_src,        ///< [in] pointer to the start of the current frame
     539              :                       const multFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     540              :     );
     541              : 
     542              :     int allocate( const pcGainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     543              :     );
     544              : 
     545              :     int processImage( void *curr_src,          ///< [in] pointer to the start of the current frame
     546              :                       const pcGainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     547              :     );
     548              : 
     549              :     int allocate( const pcMultFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     550              :     );
     551              : 
     552              :     int processImage( void *curr_src,          ///< [in] pointer to the start of the current frame
     553              :                       const pcMultFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     554              :     );
     555              : 
     556              :     int allocate( const numpccoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     557              :     );
     558              : 
     559              :     int processImage( void *curr_src,          ///< [in] pointer to the start of the current frame
     560              :                       const numpccoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     561              :     );
     562              : 
     563              :     int allocate( const acoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     564              :     );
     565              : 
     566              :     int processImage( void *curr_src,      ///< [in] pointer to the start of the current frame
     567              :                       const acoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     568              :     );
     569              : 
     570              :     int allocate( const bcoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     571              :     );
     572              : 
     573              :     int processImage( void *curr_src,      ///< [in] pointer to the start of the current frame
     574              :                       const bcoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     575              :     );
     576              : 
     577              :     int allocate( const gainCalShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     578              :     );
     579              : 
     580              :     int processImage( void *curr_src,       ///< [in] pointer to the start of the current frame
     581              :                       const gainCalShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     582              :     );
     583              : 
     584              :     int allocate( const gainCalFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     585              :     );
     586              : 
     587              :     int processImage( void *curr_src,           ///< [in] pointer to the start of the current frame
     588              :                       const gainCalFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     589              :     );
     590              : 
     591              :     int allocate( const tauShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     592              :     );
     593              : 
     594              :     int processImage( void *curr_src,   ///< [in] pointer to the start of the current frame
     595              :                       const tauShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     596              :     );
     597              : 
     598              :     int allocate( const noiseShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     599              :     );
     600              : 
     601              :     int processImage( void *curr_src,     ///< [in] pointer to the start of the current frame
     602              :                       const noiseShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     603              :     );
     604              : 
     605              :     int allocate( const wfsavgShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     606              :     );
     607              : 
     608              :     int processImage( void *curr_src,      ///< [in] pointer to the start of the current frame
     609              :                       const wfsavgShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     610              :     );
     611              : 
     612              :     int allocate( const wfsmaskShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     613              :     );
     614              : 
     615              :     int processImage( void *curr_src,       ///< [in] pointer to the start of the current frame
     616              :                       const wfsmaskShmimT & ///< [in] tag to differentiate shmimMonitor parents.
     617              :     );
     618              : 
     619              :     /// Check that all sizes and allocations have occurred
     620              :     int checkSizes();
     621              : 
     622              :   protected:
     623              :     /// Mutex for synchronizing updates.
     624              :     std::mutex m_goptMutex;
     625              : 
     626              :     /// Flag used to indicate to the goptThread that it should stop calculations ASAP
     627              :     bool m_updating{ false };
     628              : 
     629              :     /** \name Gain Optimization Thread
     630              :      *
     631              :      * @{
     632              :      */
     633              :     int m_goptThreadPrio{ 0 }; ///< Priority of the gain optimization thread.
     634              : 
     635              :     std::string m_goptThreadCpuset; ///< The cpuset to use for the gain optimization thread.
     636              : 
     637              :     std::thread m_goptThread; ///< The gain optimization thread.
     638              : 
     639              :     bool m_goptThreadInit{ true }; ///< Initialization flag for the gain optimization thread.
     640              : 
     641              :     pid_t m_goptThreadID{ 0 }; ///< gain optimization thread PID.
     642              : 
     643              :     pcf::IndiProperty m_goptThreadProp; ///< The property to hold the gain optimization thread details.
     644              : 
     645              :     sem_t m_goptSemaphore; ///< Semaphore used to synchronize the psdShmim thread and the gopt thread.
     646              : 
     647              :     float noisePSD( int n );
     648              : 
     649              :     /// Gain Optimization thread starter function
     650              :     static void goptThreadStart( modalGainOpt *p /**< [in] pointer to this */ );
     651              : 
     652              :     /// Gain optimization thread function
     653              :     /** Runs until m_shutdown is true.
     654              :      */
     655              :     void goptThreadExec();
     656              : 
     657              :     ///@}
     658              : 
     659              :   public:
     660              :     /** \name INDI
     661              :      * @{
     662              :      */
     663              : 
     664              :     pcf::IndiProperty m_indiP_autoUpdate;
     665              :     pcf::IndiProperty m_indiP_updateOnce;
     666              :     pcf::IndiProperty m_indiP_dump;
     667              : 
     668              :     pcf::IndiProperty m_indiP_opticalGain;
     669              : 
     670              :     pcf::IndiProperty m_indiP_gainGain;
     671              : 
     672              :     pcf::IndiProperty m_indiP_emg;
     673              :     pcf::IndiProperty m_indiP_psdTime;
     674              :     pcf::IndiProperty m_indiP_psdAvgTime;
     675              :     pcf::IndiProperty m_indiP_loop;
     676              :     pcf::IndiProperty m_indiP_siGain;
     677              :     pcf::IndiProperty m_indiP_siMult;
     678              :     pcf::IndiProperty m_indiP_pcGain;
     679              :     pcf::IndiProperty m_indiP_pcMult;
     680              :     pcf::IndiProperty m_indiP_pcOn;
     681              : 
     682              :     pcf::IndiProperty m_indiP_extrapOL;
     683              : 
     684              :     pcf::IndiProperty m_indiP_modesOn;
     685              : 
     686              :     pcf::IndiProperty m_indiP_opticalGainSource;
     687              :     pcf::IndiProperty m_indiP_opticalGainUpdate;
     688              : 
     689              : 
     690            0 :     INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_autoUpdate );
     691            0 :     INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_updateOnce );
     692            0 :     INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_dump );
     693            0 :     INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_opticalGain );
     694            0 :     INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_gainGain );
     695            0 :     INDI_SETCALLBACK_DECL( modalGainOpt, m_indiP_emg );
     696            0 :     INDI_SETCALLBACK_DECL( modalGainOpt, m_indiP_psdTime );
     697            0 :     INDI_SETCALLBACK_DECL( modalGainOpt, m_indiP_psdAvgTime );
     698            0 :     INDI_SETCALLBACK_DECL( modalGainOpt, m_indiP_loop );
     699            0 :     INDI_SETCALLBACK_DECL( modalGainOpt, m_indiP_siGain );
     700            0 :     INDI_SETCALLBACK_DECL( modalGainOpt, m_indiP_siMult );
     701            0 :     INDI_SETCALLBACK_DECL( modalGainOpt, m_indiP_pcGain );
     702            0 :     INDI_SETCALLBACK_DECL( modalGainOpt, m_indiP_pcMult );
     703            0 :     INDI_SETCALLBACK_DECL( modalGainOpt, m_indiP_pcOn );
     704            0 :     INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapOL );
     705              : 
     706            0 :     INDI_SETCALLBACK_DECL( modalGainOpt, m_indiP_opticalGainSource );
     707            0 :     INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_opticalGainUpdate);
     708              : 
     709              : 
     710              :     ///@}
     711              : };
     712              : 
     713            0 : modalGainOpt::modalGainOpt() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
     714              : {
     715            0 :     psdShmimMonitorT::m_getExistingFirst         = true;
     716            0 :     freqShmimMonitorT::m_getExistingFirst        = true;
     717            0 :     gainFactShmimMonitorT::m_getExistingFirst    = true;
     718            0 :     multFactShmimMonitorT::m_getExistingFirst    = true;
     719            0 :     pcGainFactShmimMonitorT::m_getExistingFirst  = true;
     720            0 :     pcMultFactShmimMonitorT::m_getExistingFirst  = true;
     721            0 :     numpccoeffShmimMonitorT::m_getExistingFirst  = true;
     722            0 :     acoeffShmimMonitorT::m_getExistingFirst      = true;
     723            0 :     bcoeffShmimMonitorT::m_getExistingFirst      = true;
     724            0 :     gainCalShmimMonitorT::m_getExistingFirst     = true;
     725            0 :     gainCalFactShmimMonitorT::m_getExistingFirst = true;
     726            0 :     tauShmimMonitorT::m_getExistingFirst         = true;
     727            0 :     noiseShmimMonitorT::m_getExistingFirst       = true;
     728            0 :     wfsavgShmimMonitorT::m_getExistingFirst      = true;
     729            0 :     wfsmaskShmimMonitorT::m_getExistingFirst     = true;
     730              : 
     731            0 :     return;
     732            0 : }
     733              : 
     734            0 : void modalGainOpt::setupConfig()
     735              : {
     736            0 :     config.add( "loop.number",
     737              :                 "",
     738              :                 "loop.number",
     739              :                 argType::Required,
     740              :                 "loop",
     741              :                 "number",
     742              :                 false,
     743              :                 "int",
     744              :                 "The number of the loop. Used to set shmim names, as in aolN_mgainfact." );
     745              : 
     746            0 :     config.add( "loop.name",
     747              :                 "",
     748              :                 "loop.name",
     749              :                 argType::Required,
     750              :                 "loop",
     751              :                 "name",
     752              :                 false,
     753              :                 "string",
     754              :                 "The name of the loop control INDI device name." );
     755              : 
     756            0 :     config.add( "loop.psdDev",
     757              :                 "",
     758              :                 "loop.psdDev",
     759              :                 argType::Required,
     760              :                 "loop",
     761              :                 "psdDev",
     762              :                 false,
     763              :                 "string",
     764              :                 "The INDI device name of the PSD calculator.  Defaults to aolN_modevalPSDs where N is loop.number." );
     765              : 
     766            0 :     config.add( "loop.autoUpdate",
     767              :                 "",
     768              :                 "loop.autoUpdate",
     769              :                 argType::Required,
     770              :                 "loop",
     771              :                 "autoUpdate",
     772              :                 false,
     773              :                 "bool",
     774              :                 "Flag controlling whether the gains are auto updated.  Also settable via INDI." );
     775              : 
     776            0 :     config.add( "loop.gainGain",
     777              :                 "",
     778              :                 "loop.gainGain",
     779              :                 argType::Required,
     780              :                 "loop",
     781              :                 "gainGain",
     782              :                 false,
     783              :                 "float",
     784              :                 "The gain to use for closed-loop gain updates.  Default is 0.1" );
     785              : 
     786            0 :     SHMIMMONITORT_SETUP_CONFIG( psdShmimMonitorT, config );
     787            0 :     SHMIMMONITORT_SETUP_CONFIG( freqShmimMonitorT, config );
     788            0 :     SHMIMMONITORT_SETUP_CONFIG( gainFactShmimMonitorT, config );
     789            0 :     SHMIMMONITORT_SETUP_CONFIG( multFactShmimMonitorT, config );
     790            0 :     SHMIMMONITORT_SETUP_CONFIG( pcGainFactShmimMonitorT, config );
     791            0 :     SHMIMMONITORT_SETUP_CONFIG( pcMultFactShmimMonitorT, config );
     792            0 :     SHMIMMONITORT_SETUP_CONFIG( numpccoeffShmimMonitorT, config );
     793            0 :     SHMIMMONITORT_SETUP_CONFIG( acoeffShmimMonitorT, config );
     794            0 :     SHMIMMONITORT_SETUP_CONFIG( bcoeffShmimMonitorT, config );
     795            0 :     SHMIMMONITORT_SETUP_CONFIG( gainCalShmimMonitorT, config );
     796            0 :     SHMIMMONITORT_SETUP_CONFIG( gainCalFactShmimMonitorT, config );
     797            0 :     SHMIMMONITORT_SETUP_CONFIG( tauShmimMonitorT, config );
     798            0 :     SHMIMMONITORT_SETUP_CONFIG( noiseShmimMonitorT, config );
     799            0 :     SHMIMMONITORT_SETUP_CONFIG( wfsavgShmimMonitorT, config );
     800            0 :     SHMIMMONITORT_SETUP_CONFIG( wfsmaskShmimMonitorT, config );
     801              : }
     802              : 
     803            0 : int modalGainOpt::loadConfigImpl( mx::app::appConfigurator &_config )
     804              : {
     805            0 :     _config( m_loopNum, "loop.number" );
     806            0 :     _config( m_loopName, "loop.name" );
     807            0 :     _config( m_autoUpdate, "loop.autoUpdate" );
     808            0 :     _config( m_autoUpdate, "loop.gainGain" );
     809              : 
     810              :     char shmim[1024];
     811              : 
     812            0 :     _config( m_psdDevice, "loop.psdDev" );
     813              : 
     814            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_clpsds", m_loopNum );
     815            0 :     psdShmimMonitorT::m_shmimName = shmim;
     816            0 :     SHMIMMONITORT_LOAD_CONFIG( psdShmimMonitorT, _config );
     817              : 
     818            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_freq", m_loopNum );
     819            0 :     freqShmimMonitorT::m_shmimName = shmim;
     820            0 :     SHMIMMONITORT_LOAD_CONFIG( freqShmimMonitorT, _config );
     821              : 
     822            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mgainfact", m_loopNum );
     823            0 :     gainFactShmimMonitorT::m_shmimName = shmim;
     824            0 :     SHMIMMONITORT_LOAD_CONFIG( gainFactShmimMonitorT, _config );
     825              : 
     826            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mmultfact", m_loopNum );
     827            0 :     multFactShmimMonitorT::m_shmimName = shmim;
     828            0 :     SHMIMMONITORT_LOAD_CONFIG( multFactShmimMonitorT, _config );
     829              : 
     830            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mpcgainfact", m_loopNum );
     831            0 :     pcGainFactShmimMonitorT::m_shmimName = shmim;
     832            0 :     SHMIMMONITORT_LOAD_CONFIG( pcGainFactShmimMonitorT, _config );
     833              : 
     834            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mpcmultfact", m_loopNum );
     835            0 :     pcMultFactShmimMonitorT::m_shmimName = shmim;
     836            0 :     SHMIMMONITORT_LOAD_CONFIG( pcMultFactShmimMonitorT, _config );
     837              : 
     838            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_numpccoeff", m_loopNum );
     839            0 :     numpccoeffShmimMonitorT::m_shmimName = shmim;
     840            0 :     SHMIMMONITORT_LOAD_CONFIG( numpccoeffShmimMonitorT, _config );
     841              : 
     842            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_acoeff", m_loopNum );
     843            0 :     acoeffShmimMonitorT::m_shmimName = shmim;
     844            0 :     SHMIMMONITORT_LOAD_CONFIG( acoeffShmimMonitorT, _config );
     845              : 
     846            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_bcoeff", m_loopNum );
     847            0 :     bcoeffShmimMonitorT::m_shmimName = shmim;
     848            0 :     SHMIMMONITORT_LOAD_CONFIG( bcoeffShmimMonitorT, _config );
     849              : 
     850            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mgaincal", m_loopNum );
     851            0 :     gainCalShmimMonitorT::m_shmimName = shmim;
     852            0 :     SHMIMMONITORT_LOAD_CONFIG( gainCalShmimMonitorT, _config );
     853              : 
     854            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mgaincalfact", m_loopNum );
     855            0 :     gainCalFactShmimMonitorT::m_shmimName = shmim;
     856            0 :     SHMIMMONITORT_LOAD_CONFIG( gainCalFactShmimMonitorT, _config );
     857              : 
     858            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_looptau", m_loopNum );
     859            0 :     tauShmimMonitorT::m_shmimName = shmim;
     860            0 :     SHMIMMONITORT_LOAD_CONFIG( tauShmimMonitorT, _config );
     861              : 
     862            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mnoiseparam", m_loopNum );
     863            0 :     noiseShmimMonitorT::m_shmimName = shmim;
     864            0 :     SHMIMMONITORT_LOAD_CONFIG( noiseShmimMonitorT, _config );
     865              : 
     866            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_wfsavg", m_loopNum );
     867            0 :     wfsavgShmimMonitorT::m_shmimName = shmim;
     868            0 :     SHMIMMONITORT_LOAD_CONFIG( wfsavgShmimMonitorT, _config );
     869              : 
     870            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_wfsmask", m_loopNum );
     871            0 :     wfsmaskShmimMonitorT::m_shmimName = shmim;
     872            0 :     SHMIMMONITORT_LOAD_CONFIG( wfsmaskShmimMonitorT, _config );
     873              : 
     874            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_olpsds", m_loopNum );
     875            0 :     m_olPSDShmimName = shmim;
     876              : 
     877            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_noisepsds", m_loopNum );
     878            0 :     m_noisePSDShmimName = shmim;
     879              : 
     880            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_clxferCurrent", m_loopNum );
     881            0 :     m_clXferCurrentShmimName = shmim;
     882              : 
     883            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_clxferSI", m_loopNum );
     884            0 :     m_clXferSIShmimName = shmim;
     885              : 
     886            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_clxferLP", m_loopNum );
     887            0 :     m_clXferLPShmimName = shmim;
     888              : 
     889            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mgainoptimal", m_loopNum );
     890            0 :     m_optGainShmimName = shmim;
     891              : 
     892            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mgainoptimalSI", m_loopNum );
     893            0 :     m_optGainSIShmimName = shmim;
     894              : 
     895            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mgainmaxSI", m_loopNum );
     896            0 :     m_maxGainSIShmimName = shmim;
     897              : 
     898            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mgainoptimalLP", m_loopNum );
     899            0 :     m_optGainLPShmimName = shmim;
     900              : 
     901            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mgainmaxLP", m_loopNum );
     902            0 :     m_maxGainLPShmimName = shmim;
     903              : 
     904            0 :     snprintf( shmim, sizeof( shmim ), "aol%d_mmodevar", m_loopNum );
     905            0 :     m_modevarShmimName = shmim;
     906              : 
     907            0 :     return 0;
     908              : }
     909              : 
     910            0 : void modalGainOpt::loadConfig()
     911              : {
     912            0 :     loadConfigImpl( config );
     913            0 : }
     914              : 
     915            0 : int modalGainOpt::appStartup()
     916              : {
     917            0 :     SHMIMMONITORT_APP_STARTUP( psdShmimMonitorT );
     918            0 :     SHMIMMONITORT_APP_STARTUP( freqShmimMonitorT );
     919            0 :     SHMIMMONITORT_APP_STARTUP( gainFactShmimMonitorT );
     920            0 :     SHMIMMONITORT_APP_STARTUP( multFactShmimMonitorT );
     921            0 :     SHMIMMONITORT_APP_STARTUP( pcGainFactShmimMonitorT );
     922            0 :     SHMIMMONITORT_APP_STARTUP( pcMultFactShmimMonitorT );
     923            0 :     SHMIMMONITORT_APP_STARTUP( numpccoeffShmimMonitorT );
     924            0 :     SHMIMMONITORT_APP_STARTUP( acoeffShmimMonitorT );
     925            0 :     SHMIMMONITORT_APP_STARTUP( bcoeffShmimMonitorT );
     926            0 :     SHMIMMONITORT_APP_STARTUP( gainCalShmimMonitorT );
     927            0 :     SHMIMMONITORT_APP_STARTUP( gainCalFactShmimMonitorT );
     928            0 :     SHMIMMONITORT_APP_STARTUP( tauShmimMonitorT );
     929            0 :     SHMIMMONITORT_APP_STARTUP( noiseShmimMonitorT );
     930            0 :     SHMIMMONITORT_APP_STARTUP( wfsavgShmimMonitorT );
     931            0 :     SHMIMMONITORT_APP_STARTUP( wfsmaskShmimMonitorT );
     932              : 
     933            0 :     CREATE_REG_INDI_NEW_TOGGLESWITCH( m_indiP_autoUpdate, "update_auto" );
     934            0 :     CREATE_REG_INDI_NEW_REQUESTSWITCH( m_indiP_updateOnce, "update_once" );
     935            0 :     CREATE_REG_INDI_NEW_REQUESTSWITCH( m_indiP_dump, "update_dump" );
     936              : 
     937            0 :     CREATE_REG_INDI_NEW_NUMBERF(
     938              :         m_indiP_opticalGain, "opticalGain", 0, 1, 0.01, "%0.01f", "Optical Gain", "Gain Opt." );
     939            0 :     CREATE_REG_INDI_NEW_NUMBERF( m_indiP_gainGain, "gainGain", 0, 1, 0.01, "%0.01f", "Gain Gain", "Gain Opt." );
     940              : 
     941            0 :     REG_INDI_SETPROP( m_indiP_emg, m_wfsDevice, "emgain" );
     942            0 :     REG_INDI_SETPROP( m_indiP_psdTime, m_psdDevice, "psdTime" );
     943            0 :     REG_INDI_SETPROP( m_indiP_psdAvgTime, m_psdDevice, "psdAvgTime" );
     944            0 :     REG_INDI_SETPROP( m_indiP_loop, m_loopName, "loop_state" );
     945            0 :     REG_INDI_SETPROP( m_indiP_siGain, m_loopName, "loop_gain" );
     946            0 :     REG_INDI_SETPROP( m_indiP_siMult, m_loopName, "loop_multcoeff" );
     947            0 :     REG_INDI_SETPROP( m_indiP_pcGain, m_loopName, "loop_pcgain" );
     948            0 :     REG_INDI_SETPROP( m_indiP_pcMult, m_loopName, "loop_pcmultcoeff" );
     949            0 :     REG_INDI_SETPROP( m_indiP_pcOn, m_loopName, "loop_pcOn" );
     950              : 
     951            0 :     CREATE_REG_INDI_NEW_TOGGLESWITCH( m_indiP_extrapOL, "extrapOL" );
     952              : 
     953            0 :     CREATE_REG_INDI_RO_NUMBER(m_indiP_modesOn, "num_modes", "number of modes", "Gain Opt.");
     954            0 :     indi::addNumberElement(m_indiP_modesOn, "current", 0, 2400, 1, "%d", "Applied Modes");
     955            0 :     indi::addNumberElement(m_indiP_modesOn, "integrator", 0, 2400, 1, "%d", "SI optimal");
     956            0 :     indi::addNumberElement(m_indiP_modesOn, "predictor", 0, 2400, 1, "%d", "LP optimal");
     957              : 
     958            0 :     REG_INDI_SETPROP( m_indiP_opticalGainSource, m_opticalGainDevice, m_opticalGainProperty );
     959              : 
     960            0 :     CREATE_REG_INDI_NEW_TOGGLESWITCH(m_indiP_opticalGainUpdate, "track_optical_gain");
     961              : 
     962            0 :     if( sem_init( &m_goptSemaphore, 0, 0 ) < 0 )
     963              :     {
     964            0 :         return log<software_critical, -1>( { __FILE__, __LINE__, errno, 0, "Initializing gopt semaphore" } );
     965              :     }
     966              : 
     967            0 :     XWCAPP_THREAD_START( m_goptThread,
     968              :                          m_goptThreadInit,
     969              :                          m_goptThreadID,
     970              :                          m_goptThreadProp,
     971              :                          m_goptThreadPrio,
     972              :                          m_goptThreadCpuset,
     973              :                          "gainopt",
     974              :                          goptThreadStart );
     975              : 
     976            0 :     state( stateCodes::OPERATING );
     977            0 :     return 0;
     978              : }
     979              : 
     980            0 : int modalGainOpt::appLogic()
     981              : {
     982            0 :     SHMIMMONITORT_APP_LOGIC( psdShmimMonitorT );
     983            0 :     SHMIMMONITORT_APP_LOGIC( freqShmimMonitorT );
     984            0 :     SHMIMMONITORT_APP_LOGIC( gainFactShmimMonitorT );
     985            0 :     SHMIMMONITORT_APP_LOGIC( multFactShmimMonitorT );
     986            0 :     SHMIMMONITORT_APP_LOGIC( pcGainFactShmimMonitorT );
     987            0 :     SHMIMMONITORT_APP_LOGIC( pcMultFactShmimMonitorT );
     988            0 :     SHMIMMONITORT_APP_LOGIC( numpccoeffShmimMonitorT );
     989            0 :     SHMIMMONITORT_APP_LOGIC( acoeffShmimMonitorT );
     990            0 :     SHMIMMONITORT_APP_LOGIC( bcoeffShmimMonitorT );
     991            0 :     SHMIMMONITORT_APP_LOGIC( gainCalShmimMonitorT );
     992            0 :     SHMIMMONITORT_APP_LOGIC( gainCalFactShmimMonitorT );
     993            0 :     SHMIMMONITORT_APP_LOGIC( tauShmimMonitorT );
     994            0 :     SHMIMMONITORT_APP_LOGIC( noiseShmimMonitorT );
     995            0 :     SHMIMMONITORT_APP_LOGIC( wfsavgShmimMonitorT );
     996            0 :     SHMIMMONITORT_APP_LOGIC( wfsmaskShmimMonitorT );
     997              : 
     998            0 :     XWCAPP_THREAD_CHECK( m_goptThread, "gainopt" );
     999              : 
    1000            0 :     SHMIMMONITORT_UPDATE_INDI( psdShmimMonitorT );
    1001            0 :     SHMIMMONITORT_UPDATE_INDI( freqShmimMonitorT );
    1002            0 :     SHMIMMONITORT_UPDATE_INDI( gainFactShmimMonitorT );
    1003            0 :     SHMIMMONITORT_UPDATE_INDI( multFactShmimMonitorT );
    1004            0 :     SHMIMMONITORT_UPDATE_INDI( pcGainFactShmimMonitorT );
    1005            0 :     SHMIMMONITORT_UPDATE_INDI( pcMultFactShmimMonitorT );
    1006            0 :     SHMIMMONITORT_UPDATE_INDI( numpccoeffShmimMonitorT );
    1007            0 :     SHMIMMONITORT_UPDATE_INDI( acoeffShmimMonitorT );
    1008            0 :     SHMIMMONITORT_UPDATE_INDI( bcoeffShmimMonitorT );
    1009            0 :     SHMIMMONITORT_UPDATE_INDI( gainCalShmimMonitorT );
    1010            0 :     SHMIMMONITORT_UPDATE_INDI( gainCalFactShmimMonitorT );
    1011            0 :     SHMIMMONITORT_UPDATE_INDI( tauShmimMonitorT );
    1012            0 :     SHMIMMONITORT_UPDATE_INDI( noiseShmimMonitorT );
    1013            0 :     SHMIMMONITORT_UPDATE_INDI( wfsavgShmimMonitorT );
    1014            0 :     SHMIMMONITORT_UPDATE_INDI( wfsmaskShmimMonitorT );
    1015              : 
    1016            0 :     if( m_autoUpdate )
    1017              :     {
    1018            0 :         updateSwitchIfChanged( m_indiP_autoUpdate, "toggle", pcf::IndiElement::On, INDI_OK );
    1019              :     }
    1020              :     else
    1021              :     {
    1022            0 :         updateSwitchIfChanged( m_indiP_autoUpdate, "toggle", pcf::IndiElement::Off, INDI_IDLE );
    1023              :     }
    1024              : 
    1025            0 :     if( m_updateOnce )
    1026              :     {
    1027            0 :         updateSwitchIfChanged( m_indiP_updateOnce, "request", pcf::IndiElement::On, INDI_OK );
    1028              :     }
    1029              :     else
    1030              :     {
    1031            0 :         updateSwitchIfChanged( m_indiP_updateOnce, "request", pcf::IndiElement::Off, INDI_IDLE );
    1032              :     }
    1033              : 
    1034            0 :     if( m_dump )
    1035              :     {
    1036            0 :         updateSwitchIfChanged( m_indiP_dump, "request", pcf::IndiElement::On, INDI_OK );
    1037              :     }
    1038              :     else
    1039              :     {
    1040            0 :         updateSwitchIfChanged( m_indiP_dump, "request", pcf::IndiElement::Off, INDI_IDLE );
    1041              :     }
    1042              : 
    1043            0 :     if( m_opticalGainUpdate )
    1044              :     {
    1045            0 :         updateSwitchIfChanged( m_indiP_opticalGainUpdate, "toggle", pcf::IndiElement::On, INDI_OK );
    1046              :     }
    1047              :     else
    1048              :     {
    1049            0 :         updateSwitchIfChanged( m_indiP_opticalGainUpdate, "toggle", pcf::IndiElement::Off, INDI_IDLE );
    1050              :     }
    1051              : 
    1052            0 :     updatesIfChanged<float>( m_indiP_opticalGain, { "current", "target" }, { m_opticalGain, m_opticalGain } );
    1053              : 
    1054            0 :     updatesIfChanged<float>( m_indiP_gainGain, { "current", "target" }, { m_gainGain, m_gainGain } );
    1055              : 
    1056            0 :     if(m_extrapOL == 0)
    1057              :     {
    1058            0 :         updateSwitchIfChanged(m_indiP_extrapOL, "toggle", pcf::IndiElement::Off);
    1059              :     }
    1060              :     else
    1061              :     {
    1062            0 :         updateSwitchIfChanged(m_indiP_extrapOL, "toggle", pcf::IndiElement::On);
    1063              :     }
    1064              : 
    1065            0 :     updatesIfChanged<int>(m_indiP_modesOn, {"current","integrator","predictor"}, {m_modesOn, m_modesOnSI, m_modesOnLP});
    1066              : 
    1067              : 
    1068            0 :     return 0;
    1069              : }
    1070              : 
    1071            0 : int modalGainOpt::appShutdown()
    1072              : {
    1073            0 :     XWCAPP_THREAD_STOP( m_goptThread );
    1074              : 
    1075            0 :     SHMIMMONITORT_APP_SHUTDOWN( psdShmimMonitorT );
    1076            0 :     SHMIMMONITORT_APP_SHUTDOWN( freqShmimMonitorT );
    1077            0 :     SHMIMMONITORT_APP_SHUTDOWN( gainFactShmimMonitorT );
    1078            0 :     SHMIMMONITORT_APP_SHUTDOWN( multFactShmimMonitorT );
    1079            0 :     SHMIMMONITORT_APP_SHUTDOWN( pcGainFactShmimMonitorT );
    1080            0 :     SHMIMMONITORT_APP_SHUTDOWN( pcMultFactShmimMonitorT );
    1081            0 :     SHMIMMONITORT_APP_SHUTDOWN( numpccoeffShmimMonitorT );
    1082            0 :     SHMIMMONITORT_APP_SHUTDOWN( acoeffShmimMonitorT );
    1083            0 :     SHMIMMONITORT_APP_SHUTDOWN( bcoeffShmimMonitorT );
    1084            0 :     SHMIMMONITORT_APP_SHUTDOWN( gainCalShmimMonitorT );
    1085            0 :     SHMIMMONITORT_APP_SHUTDOWN( gainCalFactShmimMonitorT );
    1086            0 :     SHMIMMONITORT_APP_SHUTDOWN( tauShmimMonitorT );
    1087            0 :     SHMIMMONITORT_APP_SHUTDOWN( noiseShmimMonitorT );
    1088            0 :     SHMIMMONITORT_APP_SHUTDOWN( wfsavgShmimMonitorT );
    1089            0 :     SHMIMMONITORT_APP_SHUTDOWN( wfsmaskShmimMonitorT );
    1090              : 
    1091            0 :     if( m_olPSDStream != nullptr )
    1092              :     {
    1093            0 :         ImageStreamIO_destroyIm( m_olPSDStream );
    1094            0 :         free( m_olPSDStream );
    1095            0 :         m_olPSDStream = nullptr;
    1096              : 
    1097            0 :         ImageStreamIO_destroyIm( m_noisePSDStream );
    1098            0 :         free( m_noisePSDStream );
    1099            0 :         m_noisePSDStream = nullptr;
    1100              : 
    1101            0 :         ImageStreamIO_destroyIm( m_clXferCurrentStream );
    1102            0 :         free( m_clXferCurrentStream );
    1103            0 :         m_clXferCurrentStream = nullptr;
    1104              : 
    1105            0 :         ImageStreamIO_destroyIm( m_clXferSIStream );
    1106            0 :         free( m_clXferSIStream );
    1107            0 :         m_clXferSIStream = nullptr;
    1108              : 
    1109            0 :         ImageStreamIO_destroyIm( m_clXferLPStream );
    1110            0 :         free( m_clXferLPStream );
    1111            0 :         m_clXferLPStream = nullptr;
    1112              :     }
    1113              : 
    1114            0 :     if( m_optGainStream != nullptr )
    1115              :     {
    1116            0 :         ImageStreamIO_destroyIm( m_optGainStream );
    1117            0 :         free( m_optGainStream );
    1118            0 :         m_optGainStream = nullptr;
    1119              : 
    1120            0 :         ImageStreamIO_destroyIm( m_optGainSIStream );
    1121            0 :         free( m_optGainSIStream );
    1122            0 :         m_optGainSIStream = nullptr;
    1123              : 
    1124            0 :         ImageStreamIO_destroyIm( m_maxGainSIStream );
    1125            0 :         free( m_maxGainSIStream );
    1126            0 :         m_maxGainSIStream = nullptr;
    1127              : 
    1128            0 :         ImageStreamIO_destroyIm( m_optGainLPStream );
    1129            0 :         free( m_optGainLPStream );
    1130            0 :         m_optGainLPStream = nullptr;
    1131              : 
    1132            0 :         ImageStreamIO_destroyIm( m_maxGainLPStream );
    1133            0 :         free( m_maxGainLPStream );
    1134            0 :         m_maxGainLPStream = nullptr;
    1135              : 
    1136            0 :         ImageStreamIO_destroyIm( m_modevarStream );
    1137            0 :         free( m_modevarStream );
    1138            0 :         m_modevarStream = nullptr;
    1139              :     }
    1140              : 
    1141            0 :     return 0;
    1142              : }
    1143              : 
    1144            0 : int modalGainOpt::allocatePCShmims()
    1145              : {
    1146              :     // mutex should be locked before calling this
    1147              : 
    1148            0 :     if( numpccoeffShmimMonitorT::m_smState != dev::shmimMonitorState::connected ||
    1149            0 :         numpccoeffShmimMonitorT::m_width != m_nModes || numpccoeffShmimMonitorT::m_height != 2 )
    1150              :     {
    1151            0 :         mx::improc::eigenImage<uint32_t> Npc( m_nModes, 2 );
    1152            0 :         Npc.setConstant( m_defaultNCoeff );
    1153              : 
    1154            0 :         if( numpccoeffShmimMonitorT::create( m_nModes, 2, 1, _DATATYPE_UINT32, Npc.data() ) != 0 )
    1155              :         {
    1156            0 :             return log<software_error, -1>( { __FILE__, __LINE__, "error creating numpccoeffShmim" } );
    1157              :         }
    1158              : 
    1159              :         MGO_BREADCRUMB;
    1160              : 
    1161            0 :         std::cerr << "created numppccoeff shmim\n";
    1162            0 :     }
    1163              : 
    1164            0 :     if( acoeffShmimMonitorT::m_smState != dev::shmimMonitorState::connected ||
    1165            0 :         acoeffShmimMonitorT::m_width != m_maxNCoeff + 1 || acoeffShmimMonitorT::m_height != m_nModes )
    1166              :     {
    1167            0 :         if( acoeffShmimMonitorT::create( m_maxNCoeff + 1, m_nModes, 1, _DATATYPE_FLOAT ) != 0 )
    1168              :         {
    1169            0 :             return log<software_error, -1>( { __FILE__, __LINE__, "error creating acoeffShmim" } );
    1170              :         }
    1171              : 
    1172            0 :         std::cerr << "created acoeff shmim\n";
    1173              :     }
    1174              : 
    1175            0 :     if( bcoeffShmimMonitorT::m_smState != dev::shmimMonitorState::connected ||
    1176            0 :         bcoeffShmimMonitorT::m_width != m_maxNCoeff || bcoeffShmimMonitorT::m_height != m_nModes )
    1177              :     {
    1178            0 :         if( bcoeffShmimMonitorT::create( m_maxNCoeff + 1, m_nModes, 1, _DATATYPE_FLOAT ) != 0 )
    1179              :         {
    1180            0 :             return log<software_error, -1>( { __FILE__, __LINE__, "error creating bcoeffShmim" } );
    1181              :         }
    1182              : 
    1183            0 :         std::cerr << "created bcoeff shmim\n";
    1184              :     }
    1185              : 
    1186            0 :     if( pcGainFactShmimMonitorT::m_smState != dev::shmimMonitorState::connected ||
    1187            0 :         pcGainFactShmimMonitorT::m_width != m_nModes || pcGainFactShmimMonitorT::m_height != 1 )
    1188              :     {
    1189            0 :         if( pcGainFactShmimMonitorT::create( m_nModes, 1, 1, _DATATYPE_FLOAT ) != 0 )
    1190              :         {
    1191            0 :             return log<software_error, -1>( { __FILE__, __LINE__, "error creating pcGainFactShmim" } );
    1192              :         }
    1193              : 
    1194            0 :         std::cerr << "created pcGainFact shmim\n";
    1195              :     }
    1196              : 
    1197            0 :     if( pcMultFactShmimMonitorT::m_smState != dev::shmimMonitorState::connected ||
    1198            0 :         pcMultFactShmimMonitorT::m_width != m_nModes || pcMultFactShmimMonitorT::m_height != 1 )
    1199              :     {
    1200            0 :         if( pcMultFactShmimMonitorT::create( m_nModes, 1, 1, _DATATYPE_FLOAT ) != 0 )
    1201              :         {
    1202            0 :             return log<software_error, -1>( { __FILE__, __LINE__, "error creating pcMultFactShmim" } );
    1203              :         }
    1204              : 
    1205            0 :         std::cerr << "created pcMultFact shmim\n";
    1206              :     }
    1207              : 
    1208            0 :     return 0;
    1209              : }
    1210              : 
    1211            0 : int modalGainOpt::allocate( const psdShmimT &dummy )
    1212              : {
    1213              :     static_cast<void>( dummy );
    1214              : 
    1215            0 :     m_updating = true;
    1216            0 :     std::lock_guard<std::mutex> lock( m_goptMutex );
    1217              : 
    1218            0 :     m_updating = true;
    1219              : 
    1220            0 :     m_nFreq  = psdShmimMonitorT::m_width;
    1221            0 :     m_nModes = psdShmimMonitorT::m_height;
    1222              : 
    1223            0 :     m_clPSDs.resize( m_nFreq, m_nModes );
    1224              : 
    1225            0 :     m_clXferCurrent.resize( m_nFreq, m_nModes );
    1226            0 :     m_clXferSI.resize( m_nFreq, m_nModes );
    1227            0 :     m_clXferLP.resize( m_nFreq, m_nModes );
    1228              : 
    1229            0 :     m_olPSDs.resize( m_nModes );
    1230            0 :     m_nPSDs.resize( m_nModes );
    1231              : 
    1232            0 :     for( size_t n = 0; n < m_olPSDs.size(); ++n )
    1233              :     {
    1234            0 :         m_olPSDs[n].resize( m_nFreq );
    1235            0 :         m_nPSDs[n].resize( m_nFreq );
    1236              :     }
    1237              : 
    1238            0 :     m_modeVarOL.resize( m_nModes );
    1239              : 
    1240            0 :     m_optGainSI.resize( m_nModes );
    1241            0 :     m_gmaxSI.resize( m_nModes );
    1242            0 :     m_modeVarSI.resize( m_nModes );
    1243            0 :     m_timesOnSI.resize( m_nModes, 5 );
    1244              : 
    1245              : 
    1246            0 :     m_optGainLP.resize( m_nModes );
    1247            0 :     m_modeVarLP.resize( m_nModes );
    1248            0 :     m_timesOnLP.resize( m_nModes, 5 );
    1249              : 
    1250            0 :     if( m_olPSDStream != nullptr &&
    1251            0 :         ( m_olPSDStream->md->size[0] != m_nFreq || m_olPSDStream->md->size[1] != m_nModes ) )
    1252              :     {
    1253            0 :         ImageStreamIO_destroyIm( m_olPSDStream );
    1254            0 :         free( m_olPSDStream );
    1255            0 :         m_olPSDStream = nullptr;
    1256              : 
    1257            0 :         ImageStreamIO_destroyIm( m_noisePSDStream );
    1258            0 :         free( m_noisePSDStream );
    1259            0 :         m_noisePSDStream = nullptr;
    1260              : 
    1261            0 :         ImageStreamIO_destroyIm( m_clXferCurrentStream );
    1262            0 :         free( m_clXferCurrentStream );
    1263            0 :         m_clXferCurrentStream = nullptr;
    1264              : 
    1265            0 :         ImageStreamIO_destroyIm( m_clXferSIStream );
    1266            0 :         free( m_clXferSIStream );
    1267            0 :         m_clXferSIStream = nullptr;
    1268              : 
    1269            0 :         ImageStreamIO_destroyIm( m_clXferLPStream );
    1270            0 :         free( m_clXferLPStream );
    1271            0 :         m_clXferLPStream = nullptr;
    1272              :     }
    1273              : 
    1274            0 :     if( m_olPSDStream == nullptr )
    1275              :     {
    1276            0 :         m_olPSDStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
    1277              :         uint32_t imsize[3];
    1278              : 
    1279            0 :         imsize[0] = m_nFreq;
    1280            0 :         imsize[1] = m_nModes;
    1281            0 :         imsize[2] = 1;
    1282            0 :         ImageStreamIO_createIm_gpu( m_olPSDStream,
    1283              :                                     m_olPSDShmimName.c_str(),
    1284              :                                     3,
    1285              :                                     imsize,
    1286            0 :                                     psdShmimMonitorT::m_dataType,
    1287              :                                     -1,
    1288              :                                     1,
    1289              :                                     IMAGE_NB_SEMAPHORE,
    1290              :                                     0,
    1291              :                                     CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
    1292              :                                     0 );
    1293              : 
    1294            0 :         m_olPSDStream->md->cnt0 = 0;
    1295            0 :         m_olPSDStream->md->cnt1 = 0;
    1296              : 
    1297            0 :         m_noisePSDStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
    1298              : 
    1299            0 :         ImageStreamIO_createIm_gpu( m_noisePSDStream,
    1300              :                                     m_noisePSDShmimName.c_str(),
    1301              :                                     3,
    1302              :                                     imsize,
    1303            0 :                                     psdShmimMonitorT::m_dataType,
    1304              :                                     -1,
    1305              :                                     1,
    1306              :                                     IMAGE_NB_SEMAPHORE,
    1307              :                                     0,
    1308              :                                     CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
    1309              :                                     0 );
    1310              : 
    1311            0 :         m_noisePSDStream->md->cnt0 = 0;
    1312            0 :         m_noisePSDStream->md->cnt1 = 0;
    1313              : 
    1314            0 :         m_clXferCurrentStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
    1315              : 
    1316            0 :         ImageStreamIO_createIm_gpu( m_clXferCurrentStream,
    1317              :                                     m_clXferCurrentShmimName.c_str(),
    1318              :                                     3,
    1319              :                                     imsize,
    1320            0 :                                     psdShmimMonitorT::m_dataType,
    1321              :                                     -1,
    1322              :                                     1,
    1323              :                                     IMAGE_NB_SEMAPHORE,
    1324              :                                     0,
    1325              :                                     CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
    1326              :                                     0 );
    1327              : 
    1328            0 :         m_clXferCurrentStream->md->cnt0 = 0;
    1329            0 :         m_clXferCurrentStream->md->cnt1 = 0;
    1330              : 
    1331            0 :         m_clXferSIStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
    1332              : 
    1333            0 :         ImageStreamIO_createIm_gpu( m_clXferSIStream,
    1334              :                                     m_clXferSIShmimName.c_str(),
    1335              :                                     3,
    1336              :                                     imsize,
    1337            0 :                                     psdShmimMonitorT::m_dataType,
    1338              :                                     -1,
    1339              :                                     1,
    1340              :                                     IMAGE_NB_SEMAPHORE,
    1341              :                                     0,
    1342              :                                     CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
    1343              :                                     0 );
    1344              : 
    1345            0 :         m_clXferSIStream->md->cnt0 = 0;
    1346            0 :         m_clXferSIStream->md->cnt1 = 0;
    1347              : 
    1348            0 :         m_clXferLPStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
    1349              : 
    1350            0 :         ImageStreamIO_createIm_gpu( m_clXferLPStream,
    1351              :                                     m_clXferLPShmimName.c_str(),
    1352              :                                     3,
    1353              :                                     imsize,
    1354            0 :                                     psdShmimMonitorT::m_dataType,
    1355              :                                     -1,
    1356              :                                     1,
    1357              :                                     IMAGE_NB_SEMAPHORE,
    1358              :                                     0,
    1359              :                                     CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
    1360              :                                     0 );
    1361              : 
    1362            0 :         m_clXferLPStream->md->cnt0 = 0;
    1363            0 :         m_clXferLPStream->md->cnt1 = 0;
    1364              :     }
    1365              : 
    1366            0 :     if( m_optGainStream != nullptr &&
    1367            0 :         ( m_optGainStream->md->size[0] != psdShmimMonitorT::m_height || m_optGainStream->md->size[1] != 1 ) )
    1368              :     {
    1369            0 :         ImageStreamIO_destroyIm( m_optGainStream );
    1370            0 :         free( m_optGainStream );
    1371            0 :         m_optGainStream = nullptr;
    1372              : 
    1373            0 :         ImageStreamIO_destroyIm( m_optGainSIStream );
    1374            0 :         free( m_optGainSIStream );
    1375            0 :         m_optGainSIStream = nullptr;
    1376              : 
    1377            0 :         ImageStreamIO_destroyIm( m_maxGainSIStream );
    1378            0 :         free( m_maxGainSIStream );
    1379            0 :         m_maxGainSIStream = nullptr;
    1380              : 
    1381            0 :         ImageStreamIO_destroyIm( m_optGainLPStream );
    1382            0 :         free( m_optGainLPStream );
    1383            0 :         m_optGainLPStream = nullptr;
    1384              : 
    1385            0 :         ImageStreamIO_destroyIm( m_maxGainLPStream );
    1386            0 :         free( m_maxGainLPStream );
    1387            0 :         m_maxGainLPStream = nullptr;
    1388              :     }
    1389              : 
    1390            0 :     if( m_optGainStream == nullptr )
    1391              :     {
    1392            0 :         m_optGainStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
    1393              :         uint32_t imsize[3];
    1394              : 
    1395            0 :         imsize[0] = m_nModes;
    1396            0 :         imsize[1] = 1;
    1397            0 :         imsize[2] = 1;
    1398            0 :         ImageStreamIO_createIm_gpu( m_optGainStream,
    1399              :                                     m_optGainShmimName.c_str(),
    1400              :                                     3,
    1401              :                                     imsize,
    1402            0 :                                     psdShmimMonitorT::m_dataType,
    1403              :                                     -1,
    1404              :                                     1,
    1405              :                                     IMAGE_NB_SEMAPHORE,
    1406              :                                     0,
    1407              :                                     CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
    1408              :                                     0 );
    1409              : 
    1410            0 :         m_optGainStream->md->cnt0 = 0;
    1411            0 :         m_optGainStream->md->cnt1 = 0;
    1412              : 
    1413            0 :         m_optGainSIStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
    1414              : 
    1415            0 :         ImageStreamIO_createIm_gpu( m_optGainSIStream,
    1416              :                                     m_optGainSIShmimName.c_str(),
    1417              :                                     3,
    1418              :                                     imsize,
    1419            0 :                                     psdShmimMonitorT::m_dataType,
    1420              :                                     -1,
    1421              :                                     1,
    1422              :                                     IMAGE_NB_SEMAPHORE,
    1423              :                                     0,
    1424              :                                     CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
    1425              :                                     0 );
    1426              : 
    1427            0 :         m_optGainSIStream->md->cnt0 = 0;
    1428            0 :         m_optGainSIStream->md->cnt1 = 0;
    1429              : 
    1430            0 :         m_maxGainSIStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
    1431              : 
    1432            0 :         ImageStreamIO_createIm_gpu( m_maxGainSIStream,
    1433              :                                     m_maxGainSIShmimName.c_str(),
    1434              :                                     3,
    1435              :                                     imsize,
    1436            0 :                                     psdShmimMonitorT::m_dataType,
    1437              :                                     -1,
    1438              :                                     1,
    1439              :                                     IMAGE_NB_SEMAPHORE,
    1440              :                                     0,
    1441              :                                     CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
    1442              :                                     0 );
    1443              : 
    1444            0 :         m_maxGainSIStream->md->cnt0 = 0;
    1445            0 :         m_maxGainSIStream->md->cnt1 = 0;
    1446              : 
    1447            0 :         m_optGainLPStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
    1448              : 
    1449            0 :         ImageStreamIO_createIm_gpu( m_optGainLPStream,
    1450              :                                     m_optGainLPShmimName.c_str(),
    1451              :                                     3,
    1452              :                                     imsize,
    1453            0 :                                     psdShmimMonitorT::m_dataType,
    1454              :                                     -1,
    1455              :                                     1,
    1456              :                                     IMAGE_NB_SEMAPHORE,
    1457              :                                     0,
    1458              :                                     CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
    1459              :                                     0 );
    1460              : 
    1461            0 :         m_optGainLPStream->md->cnt0 = 0;
    1462            0 :         m_optGainLPStream->md->cnt1 = 0;
    1463              : 
    1464            0 :         m_maxGainLPStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
    1465              : 
    1466            0 :         ImageStreamIO_createIm_gpu( m_maxGainLPStream,
    1467              :                                     m_maxGainLPShmimName.c_str(),
    1468              :                                     3,
    1469              :                                     imsize,
    1470            0 :                                     psdShmimMonitorT::m_dataType,
    1471              :                                     -1,
    1472              :                                     1,
    1473              :                                     IMAGE_NB_SEMAPHORE,
    1474              :                                     0,
    1475              :                                     CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
    1476              :                                     0 );
    1477              : 
    1478            0 :         m_maxGainLPStream->md->cnt0 = 0;
    1479            0 :         m_maxGainLPStream->md->cnt1 = 0;
    1480              : 
    1481            0 :         m_modevarStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
    1482              : 
    1483            0 :         imsize[0] = 3;
    1484            0 :         imsize[1] = psdShmimMonitorT::m_height;
    1485            0 :         imsize[2] = 1;
    1486              : 
    1487            0 :         ImageStreamIO_createIm_gpu( m_modevarStream,
    1488              :                                     m_modevarShmimName.c_str(),
    1489              :                                     3,
    1490              :                                     imsize,
    1491            0 :                                     psdShmimMonitorT::m_dataType,
    1492              :                                     -1,
    1493              :                                     1,
    1494              :                                     IMAGE_NB_SEMAPHORE,
    1495              :                                     0,
    1496              :                                     CIRCULAR_BUFFER | ZAXIS_TEMPORAL,
    1497              :                                     0 );
    1498              : 
    1499            0 :         m_modevarStream->md->cnt0 = 0;
    1500            0 :         m_modevarStream->md->cnt1 = 0;
    1501              :     }
    1502              : 
    1503            0 :     m_sinceChange = -1;
    1504              : 
    1505            0 :     m_updating = false;
    1506            0 :     return 0;
    1507            0 : }
    1508              : 
    1509            0 : int modalGainOpt::processImage( void *curr_src, const psdShmimT &dummy )
    1510              : {
    1511              :     static_cast<void>( dummy );
    1512              : 
    1513            0 :     ++m_sinceChange;
    1514              : 
    1515            0 :     if( m_psdAvgTime <= 0 || m_psdTime <= 0 ) // Safety check, shouldn't happen but means we need to wait.
    1516              :     {
    1517            0 :         return 0;
    1518              :     }
    1519              : 
    1520            0 :     int deadTime = ( m_psdAvgTime / m_psdTime ) / m_psdOverlapFraction;
    1521              : 
    1522            0 :     if( m_sinceChange < deadTime )
    1523              :     {
    1524            0 :         return 0;
    1525              :     }
    1526              : 
    1527              :     // Here we would update psds, but don't do that if we're in the middle of calculating
    1528            0 :     std::unique_lock<std::mutex> lock( m_goptMutex, std::try_to_lock );
    1529            0 :     if( !lock.owns_lock() )
    1530              :     {
    1531              :         ///\todo update a frame-missed counter
    1532            0 :         return 0;
    1533              :     }
    1534              : 
    1535            0 :     m_updating = true;
    1536              : 
    1537            0 :     m_clPSDs = Eigen::Map<Eigen::Array<float, -1, -1>>(
    1538            0 :         static_cast<float *>( curr_src ), psdShmimMonitorT::m_width, psdShmimMonitorT::m_height );
    1539              : 
    1540            0 :     m_updating = false;
    1541              : 
    1542            0 :     lock.unlock();
    1543              : 
    1544            0 :     if( sem_post( &m_goptSemaphore ) < 0 )
    1545              :     {
    1546            0 :         return log<software_critical, -1>( { __FILE__, __LINE__, errno, 0, "Error posting to semaphore" } );
    1547              :     }
    1548              : 
    1549            0 :     return 0;
    1550            0 : }
    1551              : 
    1552            0 : int modalGainOpt::allocate( const freqShmimT &dummy )
    1553              : {
    1554              :     static_cast<void>( dummy );
    1555              : 
    1556            0 :     return 0;
    1557              : }
    1558              : 
    1559            0 : int modalGainOpt::processImage( void *curr_src, const freqShmimT &dummy )
    1560              : {
    1561              :     static_cast<void>( dummy );
    1562              : 
    1563            0 :     if( freqShmimMonitorT::m_width != 1 )
    1564              :     {
    1565            0 :         return log<software_error, -1>( { __FILE__, __LINE__, "got freq with width not 1" } );
    1566              :     }
    1567              : 
    1568            0 :     bool change = false;
    1569              : 
    1570            0 :     float *f = static_cast<float *>( curr_src );
    1571              : 
    1572            0 :     size_t sz = freqShmimMonitorT::m_height;
    1573              : 
    1574            0 :     if( sz != m_freq.size() )
    1575              :     {
    1576            0 :         change = true;
    1577              :     }
    1578              : 
    1579            0 :     if( !change ) // f is same size
    1580              :     {
    1581            0 :         for( size_t n = 0; n < sz; ++n )
    1582              :         {
    1583            0 :             if( f[n] != m_freq[n] )
    1584              :             {
    1585            0 :                 change = true;
    1586            0 :                 break;
    1587              :             }
    1588              :         }
    1589              :     }
    1590              : 
    1591            0 :     if( change )
    1592              :     {
    1593            0 :         m_updating = true;
    1594            0 :         std::lock_guard<std::mutex> lock( m_goptMutex );
    1595              : 
    1596            0 :         m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    1597              : 
    1598            0 :         m_freq.resize( sz );
    1599              : 
    1600            0 :         for( size_t n = 0; n < sz; ++n )
    1601              :         {
    1602            0 :             m_freq[n] = f[n];
    1603              :         }
    1604              : 
    1605            0 :         m_fps = 2 * m_freq.back();
    1606              : 
    1607            0 :         m_sinceChange = -1;
    1608            0 :         m_goptUpdated = true;
    1609            0 :         m_freqUpdated = true;
    1610              : 
    1611            0 :         m_updating = false;
    1612            0 :         std::cerr << "got freq: " << sz << '\n';
    1613            0 :         std::cerr << "     fps: " << m_fps << '\n';
    1614            0 :     }
    1615              : 
    1616            0 :     return 0;
    1617              : }
    1618              : 
    1619            0 : int modalGainOpt::allocate( const gainFactShmimT &dummy )
    1620              : {
    1621              :     static_cast<void>( dummy );
    1622              : 
    1623            0 :     if( gainFactShmimMonitorT::m_height != 1 )
    1624              :     {
    1625            0 :         return log<software_error, -1>( { __FILE__, __LINE__, "got gains with height not 1" } );
    1626              :     }
    1627              : 
    1628            0 :     return 0;
    1629              : }
    1630              : 
    1631            0 : int modalGainOpt::processImage( void *curr_src, const gainFactShmimT &dummy )
    1632              : {
    1633              :     static_cast<void>( dummy );
    1634              : 
    1635            0 :     bool change = false;
    1636              : 
    1637            0 :     uint32_t w = gainFactShmimMonitorT::m_width;
    1638              : 
    1639            0 :     std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
    1640              : 
    1641            0 :     if( w != m_gainFacts.size() )
    1642              :     {
    1643            0 :         m_updating = true;
    1644            0 :         lock.lock();
    1645            0 :         m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    1646              : 
    1647            0 :         change = true;
    1648            0 :         m_gainFacts.resize( w );
    1649              :     }
    1650              : 
    1651            0 :     float *g = static_cast<float *>( curr_src );
    1652              : 
    1653            0 :     for( uint32_t n = 0; n < w; ++n )
    1654              :     {
    1655            0 :         if( change || m_gainFacts[n] != g[n] )
    1656              :         {
    1657            0 :             if( !change )
    1658              :             {
    1659            0 :                 m_updating = true;
    1660            0 :                 lock.lock();
    1661            0 :                 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    1662            0 :                 change     = true;
    1663              :             }
    1664              : 
    1665            0 :             m_gainFacts[n] = g[n];
    1666              :         }
    1667              :     }
    1668              : 
    1669            0 :     if( change )
    1670              :     {
    1671            0 :         if( m_loop )
    1672              :         {
    1673            0 :             m_sinceChange = -1;
    1674              :         }
    1675              : 
    1676            0 :         if(!m_pcOn)
    1677              :         {
    1678            0 :             int modesOn = 0;
    1679              : 
    1680            0 :             for(size_t n = 0; n < m_gainFacts.size(); ++n)
    1681              :             {
    1682            0 :                 if(m_gainFacts[n] > 0)
    1683              :                 {
    1684            0 :                     ++modesOn;
    1685              :                 }
    1686              :             }
    1687              : 
    1688            0 :             m_modesOn = modesOn;
    1689              :         }
    1690              : 
    1691              : 
    1692            0 :         m_updating = false;
    1693            0 :         std::cerr << "got gains: " << m_gainFacts.size() << "\n";
    1694              : 
    1695            0 :         lock.unlock();
    1696              :     }
    1697              : 
    1698            0 :     return 0;
    1699            0 : }
    1700              : 
    1701            0 : int modalGainOpt::allocate( const multFactShmimT &dummy )
    1702              : {
    1703              :     static_cast<void>( dummy );
    1704              : 
    1705            0 :     if( multFactShmimMonitorT::m_height != 1 )
    1706              :     {
    1707            0 :         return log<software_error, -1>( { __FILE__, __LINE__, "got multcoeffs with height not 1" } );
    1708              :     }
    1709              : 
    1710            0 :     return 0;
    1711              : }
    1712              : 
    1713            0 : int modalGainOpt::processImage( void *curr_src, const multFactShmimT &dummy )
    1714              : {
    1715              :     static_cast<void>( dummy );
    1716              : 
    1717            0 :     bool change = false;
    1718              : 
    1719            0 :     uint32_t w = multFactShmimMonitorT::m_width;
    1720              : 
    1721            0 :     std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
    1722              : 
    1723            0 :     if( w != m_multFacts.size() )
    1724              :     {
    1725            0 :         m_updating = true;
    1726            0 :         lock.lock();
    1727            0 :         m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    1728              : 
    1729            0 :         change = true;
    1730            0 :         m_multFacts.resize( w );
    1731              :     }
    1732              : 
    1733            0 :     float *m = static_cast<float *>( curr_src );
    1734              : 
    1735            0 :     for( uint32_t n = 0; n < w; ++n )
    1736              :     {
    1737            0 :         if( change || m_multFacts[n] != m[n] )
    1738              :         {
    1739            0 :             if( !change )
    1740              :             {
    1741            0 :                 m_updating = true;
    1742            0 :                 lock.lock();
    1743            0 :                 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    1744              : 
    1745            0 :                 change = true;
    1746              :             }
    1747              : 
    1748            0 :             m_multFacts[n] = m[n];
    1749              :         }
    1750              :     }
    1751              : 
    1752            0 :     if( change )
    1753              :     {
    1754            0 :         if( m_loop )
    1755              :         {
    1756            0 :             m_sinceChange = -1;
    1757              :         }
    1758              : 
    1759            0 :         m_updating    = false;
    1760            0 :         m_goptUpdated = true;
    1761              : 
    1762            0 :         std::cerr << "got mcs: " << m_multFacts.size() << " " << w << "\n";
    1763            0 :         lock.unlock();
    1764              :     }
    1765              : 
    1766            0 :     return 0;
    1767            0 : }
    1768              : 
    1769            0 : int modalGainOpt::allocate( const pcGainFactShmimT &dummy )
    1770              : {
    1771              :     static_cast<void>( dummy );
    1772              : 
    1773            0 :     if( pcGainFactShmimMonitorT::m_height != 1 )
    1774              :     {
    1775            0 :         return log<software_error, -1>( { __FILE__, __LINE__, "got pc gains with height not 1" } );
    1776              :     }
    1777              : 
    1778            0 :     return 0;
    1779              : }
    1780              : 
    1781            0 : int modalGainOpt::processImage( void *curr_src, const pcGainFactShmimT &dummy )
    1782              : {
    1783              :     static_cast<void>( dummy );
    1784              : 
    1785            0 :     bool change = false;
    1786              : 
    1787            0 :     uint32_t w = pcGainFactShmimMonitorT::m_width;
    1788              : 
    1789            0 :     std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
    1790              : 
    1791            0 :     if( w != m_pcGainFacts.size() )
    1792              :     {
    1793            0 :         m_updating = true;
    1794            0 :         lock.lock();
    1795            0 :         m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    1796              : 
    1797            0 :         change = true;
    1798            0 :         m_pcGainFacts.resize( w );
    1799              :     }
    1800              : 
    1801            0 :     float *g = static_cast<float *>( curr_src );
    1802              : 
    1803            0 :     for( uint32_t n = 0; n < w; ++n )
    1804              :     {
    1805            0 :         if( change || m_pcGainFacts[n] != g[n] )
    1806              :         {
    1807            0 :             if( !change )
    1808              :             {
    1809            0 :                 m_updating = true;
    1810            0 :                 lock.lock();
    1811            0 :                 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    1812            0 :                 change     = true;
    1813              :             }
    1814              : 
    1815            0 :             m_pcGainFacts[n] = g[n];
    1816              :         }
    1817              :     }
    1818              : 
    1819            0 :     if( change )
    1820              :     {
    1821            0 :         if( m_loop )
    1822              :         {
    1823            0 :             m_sinceChange = -1;
    1824              :         }
    1825              : 
    1826            0 :         if(m_pcOn)
    1827              :         {
    1828            0 :             int modesOn = 0;
    1829              : 
    1830            0 :             for(size_t n = 0; n < m_pcGainFacts.size(); ++n)
    1831              :             {
    1832            0 :                 if(m_gainFacts[n] > 0)
    1833              :                 {
    1834            0 :                     ++modesOn;
    1835              :                 }
    1836              :             }
    1837              : 
    1838            0 :             m_modesOn = modesOn;
    1839              :         }
    1840              : 
    1841            0 :         m_updating = false;
    1842            0 :         std::cerr << "got pc gains: " << m_pcGainFacts.size() << "\n";
    1843              : 
    1844            0 :         lock.unlock();
    1845              :     }
    1846              : 
    1847            0 :     return 0;
    1848            0 : }
    1849              : 
    1850            0 : int modalGainOpt::allocate( const pcMultFactShmimT &dummy )
    1851              : {
    1852              :     static_cast<void>( dummy );
    1853              : 
    1854            0 :     if( pcMultFactShmimMonitorT::m_height != 1 )
    1855              :     {
    1856            0 :         return log<software_error, -1>( { __FILE__, __LINE__, "got pcMultcoeffs with height not 1" } );
    1857              :     }
    1858              : 
    1859            0 :     return 0;
    1860              : }
    1861              : 
    1862            0 : int modalGainOpt::processImage( void *curr_src, const pcMultFactShmimT &dummy )
    1863              : {
    1864              :     static_cast<void>( dummy );
    1865              : 
    1866            0 :     bool change = false;
    1867              : 
    1868            0 :     uint32_t w = pcMultFactShmimMonitorT::m_width;
    1869              : 
    1870            0 :     std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
    1871              : 
    1872            0 :     if( w != m_pcMultFacts.size() )
    1873              :     {
    1874            0 :         m_updating = true;
    1875            0 :         lock.lock();
    1876            0 :         m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    1877              : 
    1878            0 :         change = true;
    1879            0 :         m_pcMultFacts.resize( w );
    1880              :     }
    1881              : 
    1882            0 :     float *m = static_cast<float *>( curr_src );
    1883              : 
    1884            0 :     for( uint32_t n = 0; n < w; ++n )
    1885              :     {
    1886            0 :         if( change || m_pcMultFacts[n] != m[n] )
    1887              :         {
    1888            0 :             if( !change )
    1889              :             {
    1890            0 :                 m_updating = true;
    1891            0 :                 lock.lock();
    1892            0 :                 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    1893              : 
    1894            0 :                 change = true;
    1895              :             }
    1896              : 
    1897            0 :             m_pcMultFacts[n] = m[n];
    1898              :         }
    1899              :     }
    1900              : 
    1901            0 :     if( change )
    1902              :     {
    1903            0 :         if( m_loop )
    1904              :         {
    1905            0 :             m_sinceChange = -1;
    1906              :         }
    1907              : 
    1908            0 :         m_updating      = false;
    1909            0 :         m_pcgoptUpdated = true;
    1910              : 
    1911            0 :         lock.unlock();
    1912            0 :         std::cerr << "got mcs: " << m_multFacts.size() << "\n";
    1913              :     }
    1914              : 
    1915            0 :     return 0;
    1916            0 : }
    1917              : 
    1918            0 : int modalGainOpt::allocate( const numpccoeffShmimT &dummy )
    1919              : {
    1920              :     static_cast<void>( dummy );
    1921              : 
    1922            0 :     if( numpccoeffShmimMonitorT::m_height != 2 )
    1923              :     {
    1924            0 :         return log<software_error, -1>( { __FILE__, __LINE__, "got numpccoeff's with height not 2" } );
    1925              :     }
    1926              : 
    1927            0 :     std::cerr << "numpccoeffShmimMonitorT::allocate\n";
    1928            0 :     return 0;
    1929              : }
    1930              : 
    1931            0 : int modalGainOpt::processImage( void *curr_src, const numpccoeffShmimT &dummy )
    1932              : {
    1933              :     static_cast<void>( dummy );
    1934              : 
    1935            0 :     bool change = false;
    1936              : 
    1937            0 :     uint32_t w = numpccoeffShmimMonitorT::m_width;
    1938              : 
    1939            0 :     std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
    1940              : 
    1941            0 :     if( w != m_Na.size() || w != m_Nb.size() || w != m_regCounter.size() || w != m_regScale.size() )
    1942              :     {
    1943            0 :         m_updating = true;
    1944            0 :         lock.lock();
    1945            0 :         m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    1946              : 
    1947            0 :         change = true;
    1948            0 :         m_Na.resize( w );
    1949            0 :         m_Nb.resize( w );
    1950              : 
    1951            0 :         m_regCounter.resize( w );
    1952              : 
    1953              :         // Initialize the regCounter
    1954            0 :         int nc = 0;
    1955              : 
    1956            0 :         for( size_t n = 0; n < m_regCounter.size(); ++n )
    1957              :         {
    1958            0 :             m_regCounter[n] = nc;
    1959            0 :             ++nc;
    1960              : 
    1961            0 :             if( nc >= m_nRegCycles )
    1962              :             {
    1963            0 :                 nc = 0;
    1964              :             }
    1965              :         }
    1966              : 
    1967            0 :         m_regScale.resize( w, -999 );
    1968            0 :         m_gmaxLP.resize( w, 0 );
    1969              :     }
    1970              : 
    1971            0 :     mx::improc::eigenMap<uint32_t> Npc( reinterpret_cast<uint32_t *>( curr_src ), w, 2 );
    1972              : 
    1973            0 :     for( uint32_t n = 0; n < w; ++n )
    1974              :     {
    1975            0 :         if( change || m_Na[n] != Npc( n, 0 ) || m_Nb[n] != Npc( n, 1 ) )
    1976              :         {
    1977            0 :             if( !change )
    1978              :             {
    1979            0 :                 m_updating = true;
    1980            0 :                 lock.lock();
    1981            0 :                 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    1982              : 
    1983            0 :                 change = true;
    1984              :             }
    1985              : 
    1986            0 :             m_Na[n] = Npc( n, 0 );
    1987            0 :             m_Nb[n] = Npc( n, 1 );
    1988              :         }
    1989              :     }
    1990              : 
    1991            0 :     if( change )
    1992              :     {
    1993            0 :         if( m_loop )
    1994              :         {
    1995            0 :             m_sinceChange = -1;
    1996              :         }
    1997              : 
    1998            0 :         m_updating    = false;
    1999            0 :         m_goptUpdated = true;
    2000              : 
    2001            0 :         lock.unlock();
    2002            0 :         std::cerr << "got num pc coeffs: " << m_Na.size() << "\n";
    2003              :     }
    2004              : 
    2005            0 :     return 0;
    2006            0 : }
    2007              : 
    2008            0 : int modalGainOpt::allocate( const acoeffShmimT &dummy )
    2009              : {
    2010              :     static_cast<void>( dummy );
    2011              : 
    2012            0 :     return 0;
    2013              : }
    2014              : 
    2015            0 : int modalGainOpt::processImage( void *curr_src, const acoeffShmimT &dummy )
    2016              : {
    2017              :     static_cast<void>( dummy );
    2018              : 
    2019            0 :     bool change = false;
    2020              : 
    2021            0 :     std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
    2022              : 
    2023            0 :     uint32_t w = acoeffShmimMonitorT::m_width;
    2024            0 :     uint32_t h = acoeffShmimMonitorT::m_height;
    2025              : 
    2026              :     // If there's a size change we lock
    2027            0 :     if( w - 1 != m_as.rows() || h != m_as.cols() || h != m_NaCurrent.size() )
    2028              :     {
    2029            0 :         m_updating = true;
    2030            0 :         lock.lock();
    2031            0 :         m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2032              : 
    2033            0 :         change = true;
    2034            0 :         m_NaCurrent.resize( h );
    2035            0 :         m_as.resize( w - 1, h );
    2036              :     }
    2037              : 
    2038            0 :     eigenMap<float> ac( reinterpret_cast<float *>( curr_src ), w, h );
    2039              : 
    2040            0 :     for( uint32_t cc = 0; cc < h; ++cc )
    2041              :     {
    2042            0 :         if( change || m_NaCurrent[cc] != ac( 0, cc ) )
    2043              :         {
    2044            0 :             if( !change )
    2045              :             {
    2046            0 :                 m_updating = true;
    2047            0 :                 lock.lock();
    2048            0 :                 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2049              : 
    2050            0 :                 change = true;
    2051              :             }
    2052              : 
    2053            0 :             m_NaCurrent[cc] = ac( 0, cc );
    2054              :         }
    2055              : 
    2056            0 :         for( uint32_t rr = 1; rr < w; ++rr )
    2057              :         {
    2058            0 :             if( change || m_as( rr - 1, cc ) != ac( rr, cc ) )
    2059              :             {
    2060            0 :                 if( !change )
    2061              :                 {
    2062            0 :                     m_updating = true;
    2063            0 :                     lock.lock();
    2064            0 :                     m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2065              : 
    2066            0 :                     change = true;
    2067              :                 }
    2068              : 
    2069            0 :                 m_as( rr - 1, cc ) = ac( rr, cc );
    2070              :             }
    2071              :         }
    2072              :     }
    2073              : 
    2074            0 :     if( change )
    2075              :     {
    2076            0 :         if( m_loop && m_pcOn )
    2077              :         {
    2078            0 :             m_sinceChange = -1;
    2079              :         }
    2080              : 
    2081            0 :         m_updating      = false;
    2082            0 :         m_pcgoptUpdated = true;
    2083              : 
    2084            0 :         lock.unlock();
    2085            0 :         std::cerr << "got a coeffs: " << w << ' ' << h << ' ' << m_NaCurrent.size() << "\n";
    2086              :     }
    2087              : 
    2088            0 :     return 0;
    2089            0 : }
    2090              : 
    2091            0 : int modalGainOpt::allocate( const bcoeffShmimT &dummy )
    2092              : {
    2093              :     static_cast<void>( dummy );
    2094              : 
    2095            0 :     return 0;
    2096              : }
    2097              : 
    2098            0 : int modalGainOpt::processImage( void *curr_src, const bcoeffShmimT &dummy )
    2099              : {
    2100              :     static_cast<void>( dummy );
    2101              : 
    2102            0 :     bool change = false;
    2103              : 
    2104            0 :     std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
    2105              : 
    2106            0 :     uint32_t w = bcoeffShmimMonitorT::m_width;
    2107            0 :     uint32_t h = bcoeffShmimMonitorT::m_height;
    2108              : 
    2109              :     // If there's a size change we lock
    2110            0 :     if( w - 1 != m_bs.rows() || h != m_bs.cols() || h != m_NbCurrent.size() )
    2111              :     {
    2112            0 :         m_updating = true;
    2113            0 :         lock.lock();
    2114            0 :         m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2115              : 
    2116            0 :         change = true;
    2117              : 
    2118            0 :         m_NbCurrent.resize( h );
    2119            0 :         m_bs.resize( w - 1, h );
    2120              :     }
    2121              : 
    2122            0 :     eigenMap<float> bc( reinterpret_cast<float *>( curr_src ), w, h );
    2123              : 
    2124            0 :     for( uint32_t cc = 0; cc < h; ++cc )
    2125              :     {
    2126            0 :         if( change || m_NbCurrent[cc] != bc( 0, cc ) )
    2127              :         {
    2128            0 :             if( !change )
    2129              :             {
    2130            0 :                 m_updating = true;
    2131            0 :                 lock.lock();
    2132            0 :                 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2133              : 
    2134            0 :                 change = true;
    2135              :             }
    2136              : 
    2137            0 :             m_NbCurrent[cc] = bc( 0, cc );
    2138              :         }
    2139              : 
    2140            0 :         for( uint32_t rr = 1; rr < w; ++rr )
    2141              :         {
    2142            0 :             if( change || m_bs( rr - 1, cc ) != bc( rr, cc ) )
    2143              :             {
    2144            0 :                 if( !change )
    2145              :                 {
    2146            0 :                     m_updating = true;
    2147            0 :                     lock.lock();
    2148            0 :                     m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2149              : 
    2150            0 :                     change = true;
    2151              :                 }
    2152              : 
    2153            0 :                 m_bs( rr - 1, cc ) = bc( rr, cc );
    2154              :             }
    2155              :         }
    2156              :     }
    2157              : 
    2158            0 :     if( change )
    2159              :     {
    2160            0 :         if( m_loop && m_pcOn )
    2161              :         {
    2162            0 :             m_sinceChange = -1;
    2163              :         }
    2164              : 
    2165            0 :         m_updating      = false;
    2166            0 :         m_pcgoptUpdated = true;
    2167              : 
    2168            0 :         std::cerr << "got b coeffs: " << w << ' ' << h << ' ' << m_NbCurrent.size() << "\n";
    2169              : 
    2170            0 :         lock.unlock();
    2171              :     }
    2172              : 
    2173            0 :     return 0;
    2174            0 : }
    2175              : 
    2176            0 : int modalGainOpt::allocate( const gainCalShmimT &dummy )
    2177              : {
    2178              :     static_cast<void>( dummy );
    2179              : 
    2180            0 :     return 0;
    2181              : }
    2182              : 
    2183            0 : int modalGainOpt::processImage( void *curr_src, const gainCalShmimT &dummy )
    2184              : {
    2185              :     static_cast<void>( dummy );
    2186              : 
    2187            0 :     if( gainCalShmimMonitorT::m_height != 1 )
    2188              :     {
    2189            0 :         return log<software_error, -1>( { __FILE__, __LINE__, "got gainCals with height not 1" } );
    2190              :     }
    2191              : 
    2192            0 :     bool change = false;
    2193              : 
    2194            0 :     uint32_t w = gainCalShmimMonitorT::m_width;
    2195              : 
    2196            0 :     std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
    2197              : 
    2198            0 :     if( w != m_gainCals.size() )
    2199              :     {
    2200            0 :         m_updating = true;
    2201            0 :         lock.lock();
    2202              : 
    2203            0 :         m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2204              : 
    2205            0 :         change = true;
    2206            0 :         m_gainCals.resize( w );
    2207              :     }
    2208              : 
    2209            0 :     float *g = static_cast<float *>( curr_src );
    2210              : 
    2211            0 :     for( uint32_t n = 0; n < w; ++n )
    2212              :     {
    2213            0 :         if( change || m_gainCals[n] != g[n] )
    2214              :         {
    2215            0 :             if( !change )
    2216              :             {
    2217            0 :                 m_updating = true;
    2218            0 :                 lock.lock();
    2219            0 :                 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2220              : 
    2221            0 :                 change = true;
    2222              :             }
    2223              : 
    2224            0 :             m_gainCals[n] = g[n];
    2225              :         }
    2226              :     }
    2227              : 
    2228            0 :     if( change )
    2229              :     {
    2230            0 :         m_sinceChange = -1;
    2231            0 :         m_updating    = false;
    2232            0 :         std::cerr << "got gainCals: " << m_gainCals.size() << "\n";
    2233            0 :         lock.unlock();
    2234              :     }
    2235              : 
    2236            0 :     return 0;
    2237            0 : }
    2238              : 
    2239            0 : int modalGainOpt::allocate( const gainCalFactShmimT &dummy )
    2240              : {
    2241              :     static_cast<void>( dummy );
    2242              : 
    2243            0 :     return 0;
    2244              : }
    2245              : 
    2246            0 : int modalGainOpt::processImage( void *curr_src, const gainCalFactShmimT &dummy )
    2247              : {
    2248              :     static_cast<void>( dummy );
    2249              : 
    2250            0 :     if( gainCalFactShmimMonitorT::m_height != 1 )
    2251              :     {
    2252            0 :         return log<software_error, -1>( { __FILE__, __LINE__, "got gainCalFacts with height not 1" } );
    2253              :     }
    2254              : 
    2255            0 :     bool change = false;
    2256              : 
    2257            0 :     uint32_t w = gainCalFactShmimMonitorT::m_width;
    2258              : 
    2259            0 :     std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
    2260              : 
    2261            0 :     if( w != m_gainCalFacts.size() )
    2262              :     {
    2263            0 :         m_updating = true;
    2264            0 :         lock.lock();
    2265            0 :         m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2266              : 
    2267            0 :         change = true;
    2268            0 :         m_gainCalFacts.resize( w );
    2269              :     }
    2270              : 
    2271            0 :     float *g = static_cast<float *>( curr_src );
    2272              : 
    2273            0 :     for( uint32_t n = 0; n < w; ++n )
    2274              :     {
    2275            0 :         if( change || m_gainCalFacts[n] != g[n] )
    2276              :         {
    2277            0 :             if( !change )
    2278              :             {
    2279            0 :                 m_updating = true;
    2280            0 :                 lock.lock();
    2281            0 :                 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2282              : 
    2283            0 :                 change = true;
    2284              :             }
    2285              : 
    2286            0 :             m_gainCalFacts[n] = g[n];
    2287              :         }
    2288              :     }
    2289              : 
    2290            0 :     if( change )
    2291              :     {
    2292            0 :         m_sinceChange = -1;
    2293            0 :         m_updating    = false;
    2294            0 :         std::cerr << "got gainCalsFacts: " << m_gainCalFacts.size() << "\n";
    2295            0 :         lock.unlock();
    2296              :     }
    2297              : 
    2298            0 :     return 0;
    2299            0 : }
    2300              : 
    2301            0 : int modalGainOpt::allocate( const tauShmimT &dummy )
    2302              : {
    2303              :     static_cast<void>( dummy );
    2304              : 
    2305            0 :     return 0;
    2306              : }
    2307              : 
    2308            0 : int modalGainOpt::processImage( void *curr_src, const tauShmimT &dummy )
    2309              : {
    2310              :     static_cast<void>( dummy );
    2311              : 
    2312            0 :     if( tauShmimMonitorT::m_height != 1 )
    2313              :     {
    2314            0 :         return log<software_error, -1>( { __FILE__, __LINE__, "got tau with height not 1" } );
    2315              :     }
    2316              : 
    2317            0 :     bool change = false;
    2318              : 
    2319            0 :     uint32_t w = tauShmimMonitorT::m_width;
    2320              : 
    2321            0 :     std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
    2322              : 
    2323            0 :     if( w != m_taus.size() )
    2324              :     {
    2325            0 :         m_updating = true;
    2326            0 :         lock.lock();
    2327            0 :         m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2328              : 
    2329            0 :         change = true;
    2330            0 :         m_taus.resize( w );
    2331              :     }
    2332              : 
    2333            0 :     float *t = static_cast<float *>( curr_src );
    2334              : 
    2335            0 :     for( uint32_t n = 0; n < w; ++n )
    2336              :     {
    2337            0 :         if( change || m_taus[n] != t[n] )
    2338              :         {
    2339            0 :             if( !change )
    2340              :             {
    2341            0 :                 m_updating = true;
    2342            0 :                 lock.lock();
    2343            0 :                 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2344              : 
    2345            0 :                 change = true;
    2346              :             }
    2347              : 
    2348            0 :             m_taus[n] = t[n];
    2349              :         }
    2350              :     }
    2351              : 
    2352            0 :     if( change )
    2353              :     {
    2354            0 :         m_sinceChange = -1;
    2355            0 :         m_updating    = false;
    2356            0 :         m_goptUpdated = true;
    2357            0 :         std::cerr << "got taus: " << m_taus.size() << "\n";
    2358            0 :         lock.unlock();
    2359              :     }
    2360            0 :     return 0;
    2361            0 : }
    2362              : 
    2363            0 : int modalGainOpt::allocate( const noiseShmimT &dummy )
    2364              : {
    2365              :     static_cast<void>( dummy );
    2366              : 
    2367            0 :     return 0;
    2368              : }
    2369              : 
    2370            0 : int modalGainOpt::processImage( void *curr_src, const noiseShmimT &dummy )
    2371              : {
    2372              :     static_cast<void>( dummy );
    2373              : 
    2374            0 :     if( noiseShmimMonitorT::m_width != 3 )
    2375              :     {
    2376            0 :         return log<software_error, -1>( { __FILE__, __LINE__, "got tau with width not 3" } );
    2377              :     }
    2378              : 
    2379            0 :     bool change = false;
    2380              : 
    2381            0 :     uint32_t h = noiseShmimMonitorT::m_height;
    2382              : 
    2383            0 :     std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
    2384              : 
    2385            0 :     if( h != m_noiseParams.cols() )
    2386              :     {
    2387            0 :         m_updating = true;
    2388            0 :         lock.lock();
    2389            0 :         m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2390              : 
    2391            0 :         change = true;
    2392            0 :         m_noiseParams.resize( 3, h );
    2393              :     }
    2394              : 
    2395            0 :     mx::improc::eigenMap<float> np( static_cast<float *>( curr_src ), 3, h );
    2396              : 
    2397            0 :     for( uint32_t n = 0; n < h; ++n )
    2398              :     {
    2399            0 :         if( change || m_noiseParams( 0, n ) != np( 0, n ) || m_noiseParams( 1, n ) != np( 1, n ) ||
    2400            0 :             m_noiseParams( 2, n ) != np( 2, n ) )
    2401              :         {
    2402            0 :             if( !change )
    2403              :             {
    2404            0 :                 m_updating = true;
    2405            0 :                 lock.lock();
    2406            0 :                 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
    2407              : 
    2408            0 :                 change = true;
    2409              :             }
    2410              : 
    2411            0 :             m_noiseParams.col( n ) = np.col( n );
    2412              :         }
    2413              :     }
    2414              : 
    2415            0 :     if( change )
    2416              :     {
    2417            0 :         m_sinceChange = -1;
    2418            0 :         m_updating    = false;
    2419            0 :         m_goptUpdated = true;
    2420            0 :         std::cerr << "got noise params: " << m_noiseParams.rows() << " x " << m_noiseParams.cols() << "\n";
    2421            0 :         lock.unlock();
    2422              :     }
    2423            0 :     return 0;
    2424            0 : }
    2425              : 
    2426            0 : int modalGainOpt::allocate( const wfsavgShmimT &dummy )
    2427              : {
    2428              :     static_cast<void>( dummy );
    2429              : 
    2430            0 :     std::cerr << "Got WFS avg: " << wfsavgShmimMonitorT::m_width << " x " << wfsavgShmimMonitorT::m_height << '\n';
    2431            0 :     return 0;
    2432              : }
    2433              : 
    2434            0 : int modalGainOpt::processImage( void *curr_src, const wfsavgShmimT &dummy )
    2435              : {
    2436              :     static_cast<void>( dummy );
    2437              : 
    2438            0 :     m_wfsavg = mx::improc::eigenMap<float>(
    2439            0 :         reinterpret_cast<float *>( curr_src ), wfsavgShmimMonitorT::m_width, wfsavgShmimMonitorT::m_height );
    2440              : 
    2441            0 :     if( m_wfsavg.rows() == m_wfsmask.rows() && m_wfsavg.cols() == m_wfsmask.cols() )
    2442              :     {
    2443            0 :         m_counts = ( m_wfsavg * m_wfsmask ).sum();
    2444              : 
    2445              :         // std::cerr << "counts: " << m_counts << '\n';
    2446              :     }
    2447              : 
    2448            0 :     return 0;
    2449              : }
    2450              : 
    2451            0 : int modalGainOpt::allocate( const wfsmaskShmimT &dummy )
    2452              : {
    2453              :     static_cast<void>( dummy );
    2454              : 
    2455            0 :     std::cerr << "Got WFS mask: " << wfsmaskShmimMonitorT::m_width << " x " << wfsmaskShmimMonitorT::m_height << '\n';
    2456            0 :     return 0;
    2457              : }
    2458              : 
    2459            0 : int modalGainOpt::processImage( void *curr_src, const wfsmaskShmimT &dummy )
    2460              : {
    2461              :     static_cast<void>( dummy );
    2462              : 
    2463            0 :     m_wfsmask = mx::improc::eigenMap<float>(
    2464            0 :         reinterpret_cast<float *>( curr_src ), wfsmaskShmimMonitorT::m_width, wfsmaskShmimMonitorT::m_height );
    2465              : 
    2466            0 :     m_npix = m_wfsmask.sum();
    2467              : 
    2468            0 :     if( m_wfsavg.rows() == m_wfsmask.rows() && m_wfsavg.cols() == m_wfsmask.cols() )
    2469              :     {
    2470            0 :         m_counts = ( m_wfsavg * m_wfsmask ).sum();
    2471              :     }
    2472              : 
    2473            0 :     return 0;
    2474              : }
    2475              : 
    2476            0 : int modalGainOpt::checkSizes()
    2477              : {
    2478            0 :     static std::vector<bool> logged( 50, false );
    2479              : 
    2480            0 :     int L = 0;
    2481            0 :     if( m_clPSDs.rows() == 0 || m_clPSDs.cols() == 0 ) // somehow here without any data
    2482              :     {
    2483            0 :         if( !logged[L] )
    2484              :         {
    2485            0 :             log<software_error>( { __FILE__, __LINE__, "PSDs have not been updated" } );
    2486              :         }
    2487            0 :         logged[L] = true;
    2488            0 :         return -1;
    2489              :     }
    2490            0 :     logged[L++] = false;
    2491              : 
    2492            0 :     if( static_cast<size_t>( m_clPSDs.rows() ) != m_freq.size() )
    2493              :     {
    2494            0 :         if( !logged[L] )
    2495              :         {
    2496            0 :             log<software_error>( { __FILE__, __LINE__, "PSDs and freq size mismatch" } );
    2497              :         }
    2498            0 :         logged[L] = true;
    2499            0 :         return -1;
    2500              :     }
    2501            0 :     logged[L++] = false;
    2502              : 
    2503            0 :     if( m_nModes != m_gainFacts.size() )
    2504              :     {
    2505            0 :         if( !logged[L] )
    2506              :         {
    2507            0 :             log<software_error>( { __FILE__, __LINE__, "PSDs and gains number of modes mismatch" } );
    2508              :         }
    2509            0 :         logged[L] = true;
    2510            0 :         return -1;
    2511              :     }
    2512            0 :     logged[L++] = false;
    2513              : 
    2514            0 :     if( m_nModes != m_multFacts.size() )
    2515              :     {
    2516            0 :         if( !logged[L] )
    2517              :         {
    2518            0 :             log<software_error>( { __FILE__, __LINE__, "PSDs and mult coeffs number of modes mismatch" } );
    2519              :         }
    2520            0 :         logged[L] = true;
    2521            0 :         return -1;
    2522              :     }
    2523            0 :     logged[L++] = false;
    2524              : 
    2525            0 :     if( m_nModes != m_gainCals.size() )
    2526              :     {
    2527            0 :         if( !logged[L] )
    2528              :         {
    2529            0 :             log<software_error>( { __FILE__, __LINE__, "PSDs and gain cals number of modes mismatch" } );
    2530              :         }
    2531            0 :         logged[L] = true;
    2532            0 :         return -1;
    2533              :     }
    2534            0 :     logged[L++] = false;
    2535              : 
    2536            0 :     if( m_nModes != m_gainCalFacts.size() )
    2537              :     {
    2538            0 :         if( !logged[L] )
    2539              :         {
    2540            0 :             log<software_error>( { __FILE__, __LINE__, "PSDs and gain cal facts number of modes mismatch" } );
    2541              :         }
    2542            0 :         logged[L] = true;
    2543            0 :         return -1;
    2544              :     }
    2545            0 :     logged[L++] = false;
    2546              : 
    2547            0 :     if( m_nModes != m_taus.size() )
    2548              :     {
    2549            0 :         if( !logged[L] )
    2550              :         {
    2551            0 :             log<software_error>( { __FILE__, __LINE__, "Loop taus have not been set" } );
    2552              :         }
    2553            0 :         logged[L] = true;
    2554            0 :         return -1;
    2555              :     }
    2556            0 :     logged[L++] = false;
    2557              : 
    2558              :     /*if( m_clPSDs.cols() != m_noiseParams.cols() || m_noiseParams.rows() != 3 )
    2559              :     {
    2560              :         if( !logged[L] )
    2561              :         {
    2562              :             log<software_error>( { __FILE__, __LINE__, "noise params have not been set" } );
    2563              :         }
    2564              :         logged[L] = true;
    2565              :         return -1;
    2566              :     }
    2567              :     logged[L++] = false;*/
    2568              : 
    2569            0 :     if( m_fps <= 0 )
    2570              :     {
    2571            0 :         if( !logged[L] )
    2572              :         {
    2573            0 :             log<software_error>( { __FILE__, __LINE__, "Loop fps has not been set" } );
    2574              :         }
    2575            0 :         logged[L] = true;
    2576            0 :         return -1;
    2577              :     }
    2578            0 :     logged[L++] = false;
    2579              : 
    2580            0 :     if( m_olPSDStream == nullptr )
    2581              :     {
    2582            0 :         if( !logged[L] )
    2583              :         {
    2584            0 :             log<software_error>( { __FILE__, __LINE__, "m_olPSDStream is not allocated" } );
    2585              :         }
    2586            0 :         logged[L] = true;
    2587            0 :         return -1;
    2588              :     }
    2589            0 :     logged[L++] = false;
    2590              : 
    2591            0 :     if( m_noisePSDStream == nullptr )
    2592              :     {
    2593            0 :         if( !logged[L] )
    2594              :         {
    2595            0 :             log<software_error>( { __FILE__, __LINE__, "m_noisePSDStream is not allocated" } );
    2596              :         }
    2597            0 :         logged[L] = true;
    2598            0 :         return -1;
    2599              :     }
    2600            0 :     logged[L++] = false;
    2601              : 
    2602            0 :     if( m_clXferCurrentStream == nullptr )
    2603              :     {
    2604            0 :         if( !logged[L] )
    2605              :         {
    2606            0 :             log<software_error>( { __FILE__, __LINE__, "m_clXferCurrentStream is not allocated" } );
    2607              :         }
    2608            0 :         logged[L] = true;
    2609            0 :         return -1;
    2610              :     }
    2611            0 :     logged[L++] = false;
    2612              : 
    2613            0 :     if( m_clXferSIStream == nullptr )
    2614              :     {
    2615            0 :         if( !logged[L] )
    2616              :         {
    2617            0 :             log<software_error>( { __FILE__, __LINE__, "m_clXferSIStream is not allocated" } );
    2618              :         }
    2619            0 :         logged[L] = true;
    2620            0 :         return -1;
    2621              :     }
    2622            0 :     logged[L++] = false;
    2623              : 
    2624            0 :     if( m_optGainStream == nullptr )
    2625              :     {
    2626            0 :         if( !logged[L] )
    2627              :         {
    2628            0 :             log<software_error>( { __FILE__, __LINE__, "optGainsStream is not allocated" } );
    2629              :         }
    2630            0 :         logged[L] = true;
    2631            0 :         return -1;
    2632              :     }
    2633            0 :     logged[L++] = false;
    2634              : 
    2635            0 :     if( m_optGainSIStream == nullptr )
    2636              :     {
    2637            0 :         if( !logged[L] )
    2638              :         {
    2639            0 :             log<software_error>( { __FILE__, __LINE__, "optGainsStream SI is not allocated" } );
    2640              :         }
    2641            0 :         logged[L] = true;
    2642            0 :         return -1;
    2643              :     }
    2644            0 :     logged[L++] = false;
    2645              : 
    2646              :     // Check the PC shmims that we don't automatically create
    2647            0 :     if( m_Na.size() != m_nModes || m_NaCurrent.size() != m_nModes || (size_t)m_as.cols() != m_nModes ||
    2648            0 :         m_Nb.size() != m_nModes || m_NbCurrent.size() != m_nModes || (size_t)m_bs.cols() != m_nModes ||
    2649            0 :         m_pcGainFacts.size() != m_nModes || m_pcMultFacts.size() != m_nModes )
    2650              :     {
    2651              : 
    2652            0 :         if( allocatePCShmims() < 0 )
    2653              :         {
    2654            0 :             log<software_error>( { __FILE__, __LINE__, "error allocating PC shmims" } );
    2655              :         }
    2656              : 
    2657            0 :         if( m_Na.size() != m_nModes || m_NaCurrent.size() != m_nModes || (size_t)m_as.cols() != m_nModes ||
    2658            0 :             m_Nb.size() != m_nModes || m_NbCurrent.size() != m_nModes || (size_t)m_bs.cols() != m_nModes ||
    2659            0 :             m_pcGainFacts.size() != m_nModes || m_pcMultFacts.size() != m_nModes )
    2660              :         {
    2661              : 
    2662            0 :             if( !logged[L] )
    2663              :             {
    2664            0 :                 log<software_error>( { __FILE__, __LINE__, "PC shmims not allcoated" } );
    2665              :             }
    2666            0 :             logged[L] = true;
    2667            0 :             return -1;
    2668              :         }
    2669              :         else
    2670              :         {
    2671            0 :             logged[L] = false;
    2672              :         }
    2673              :     }
    2674              :     else
    2675              :     {
    2676            0 :         logged[L] = false;
    2677              :     }
    2678            0 :     ++L;
    2679              : 
    2680            0 :     if( m_clXferLPStream == nullptr )
    2681              :     {
    2682            0 :         if( !logged[L] )
    2683              :         {
    2684            0 :             log<software_error>( { __FILE__, __LINE__, "m_clXferLPStream is not allocated" } );
    2685              :         }
    2686            0 :         logged[L] = true;
    2687            0 :         return -1;
    2688              :     }
    2689            0 :     logged[L++] = false;
    2690              : 
    2691            0 :     if( m_optGainLPStream == nullptr )
    2692              :     {
    2693            0 :         if( !logged[L] )
    2694              :         {
    2695            0 :             log<software_error>( { __FILE__, __LINE__, "m_optGainLPStream is not allocated" } );
    2696              :         }
    2697            0 :         logged[L] = true;
    2698            0 :         return -1;
    2699              :     }
    2700            0 :     logged[L++] = false;
    2701              : 
    2702            0 :     if( m_nModes != m_optGainLP.size() )
    2703              :     {
    2704            0 :         if( !logged[L] )
    2705              :         {
    2706            0 :             log<software_error>( { __FILE__, __LINE__, "m_optGainLP is not allocated" } );
    2707              :         }
    2708            0 :         logged[L] = true;
    2709            0 :         return -1;
    2710              :     }
    2711            0 :     logged[L++] = false;
    2712              : 
    2713            0 :     return 0;
    2714              : }
    2715              : 
    2716            0 : float modalGainOpt::noisePSD( int n )
    2717              : {
    2718            0 :     float mc = m_noiseParams( 1, n ) * m_counts / m_emg;
    2719              : 
    2720            0 :     float snr2 = ( mc * mc ) / ( mc + m_npix * pow( m_noiseParams( 2, n ) / m_emg, 2 ) );
    2721              : 
    2722            0 :     return 0.05 * m_noiseParams( 0, n ) / snr2;
    2723              : }
    2724              : 
    2725            0 : void modalGainOpt::goptThreadStart( modalGainOpt *p )
    2726              : {
    2727            0 :     p->goptThreadExec();
    2728            0 : }
    2729              : 
    2730            0 : void modalGainOpt::goptThreadExec()
    2731              : {
    2732            0 :     m_goptThreadID = syscall( SYS_gettid );
    2733              : 
    2734            0 :     while( m_goptThreadInit == true && shutdown() == 0 )
    2735              :     {
    2736            0 :         sleep( 1 );
    2737              :     }
    2738              : 
    2739            0 :     while( shutdown() == 0 )
    2740              :     {
    2741              :         timespec ts;
    2742            0 :         XWC_SEM_WAIT_TS_RETVOID( ts, 1, 0 );
    2743              : 
    2744            0 :         if( sem_timedwait( &m_goptSemaphore, &ts ) == 0 )
    2745              :         {
    2746            0 :             std::lock_guard<std::mutex> lock( m_goptMutex );
    2747              : 
    2748            0 :             if( checkSizes() < 0 )
    2749              :             {
    2750            0 :                 std::cerr << "check sizes failed\n";
    2751            0 :                 continue; // we just wait
    2752              :             }
    2753              : 
    2754              :             // m_doPCCalcs = false;
    2755              : 
    2756            0 :             if( m_goptUpdated || m_pcgoptUpdated || m_freqUpdated || m_goptCurrent.size() != m_gainFacts.size() )
    2757              :             {
    2758            0 :                 if( m_goptCurrent.size() != m_gainFacts.size() )
    2759              :                 {
    2760            0 :                     m_freqUpdated = true; // force freq update in this case
    2761              :                 }
    2762              : 
    2763            0 :                 std::cerr << "updating gopt structures\n";
    2764              : 
    2765            0 :                 m_goptCurrent.resize( m_gainFacts.size() );
    2766            0 :                 m_goptSI.resize( m_gainFacts.size() );
    2767            0 :                 m_goptLP.resize( m_gainFacts.size() );
    2768            0 :                 m_linPred.resize( m_gainFacts.size() );
    2769              : 
    2770            0 :                 for( size_t n = 0; n < m_goptCurrent.size(); ++n )
    2771              :                 {
    2772            0 :                     m_goptCurrent[n].Ti( 1.0 / m_fps );
    2773            0 :                     m_goptCurrent[n].tau( m_taus[n] );
    2774              : 
    2775            0 :                     m_goptSI[n].Ti( 1.0 / m_fps );
    2776            0 :                     m_goptSI[n].tau( m_taus[n] );
    2777              : 
    2778            0 :                     m_goptLP[n].Ti( 1.0 / m_fps );
    2779            0 :                     m_goptLP[n].tau( m_taus[n] );
    2780              : 
    2781            0 :                     if( !m_pcOn )
    2782              :                     {
    2783            0 :                         m_goptCurrent[n].setLeakyIntegrator( m_mult * m_multFacts[n] );
    2784              :                     }
    2785              :                     else
    2786              :                     {
    2787            0 :                         std::vector<float> ta( m_NaCurrent[n] );
    2788            0 :                         for( size_t m = 0; m < ta.size(); ++m )
    2789              :                         {
    2790            0 :                             ta[m] = m_as( m, n );
    2791              :                         }
    2792            0 :                         m_goptCurrent[n].a( ta );
    2793              : 
    2794            0 :                         std::vector<float> tb( m_NbCurrent[n] );
    2795            0 :                         for( size_t m = 0; m < tb.size(); ++m )
    2796              :                         {
    2797            0 :                             tb[m] = m_bs( m, n );
    2798              :                         }
    2799            0 :                         m_goptCurrent[n].b( tb );
    2800              : 
    2801            0 :                         m_goptCurrent[n].remember( m_pcMult * m_pcMultFacts[n] );
    2802            0 :                     }
    2803              : 
    2804            0 :                     m_goptSI[n].setLeakyIntegrator( m_mult * m_multFacts[n] );
    2805              : 
    2806            0 :                     if( m_freqUpdated )
    2807              :                     {
    2808            0 :                         m_goptCurrent[n].f( m_freq );
    2809            0 :                         m_goptSI[n].f( m_freq );
    2810            0 :                         m_goptLP[n].f( m_freq );
    2811              :                     }
    2812              : 
    2813            0 :                     m_gmaxSI[n] = m_goptSI[n].maxStableGain();
    2814              :                 }
    2815              : 
    2816            0 :                 m_goptUpdated   = false;
    2817            0 :                 m_pcgoptUpdated = false;
    2818            0 :                 m_freqUpdated   = false;
    2819              : 
    2820            0 :                 std::cerr << "done.\n";
    2821              :             }
    2822              : 
    2823              :             MGO_BREADCRUMB;
    2824            0 :             if( m_updating )
    2825              :             {
    2826            0 :                 continue;
    2827              :             }
    2828              : 
    2829            0 :             timePointT t0 = std::chrono::steady_clock::now();
    2830              : 
    2831              :             MGO_BREADCRUMB;
    2832              : 
    2833            0 :             int off = 0;
    2834            0 :             int offLP = 0;
    2835              : 
    2836            0 : #pragma omp parallel for num_threads( 15 )
    2837              :             for( size_t n = 0; n < m_goptCurrent.size(); ++n )
    2838              :             {
    2839              :                 if( m_updating || m_shutdown )
    2840              :                 {
    2841              :                     continue; // don't break b/c of omp
    2842              :                 }
    2843              : 
    2844              :                 if( !m_pcOn )
    2845              :                 {
    2846              :                     MGO_BREADCRUMB;
    2847              : 
    2848              :                     for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    2849              :                     {
    2850              :                         m_clXferCurrent( f, n ) =
    2851              :                             m_goptCurrent[n].clETF2( f, m_gain * m_gainFacts[n] * m_gainCals[n] * m_opticalGain );
    2852              :                     }
    2853              :                 }
    2854              :                 else
    2855              :                 {
    2856              :                     for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    2857              :                     {
    2858              :                         m_clXferCurrent( f, n ) =
    2859              :                             m_goptCurrent[n].clETF2( f, m_pcGain * m_pcGainFacts[n] * m_gainCals[n] * m_opticalGain );
    2860              :                     }
    2861              :                 }
    2862              : 
    2863              :                 MGO_BREADCRUMB;
    2864              :                 // Calculate the OL PSD with the current gopt (PC or SI)
    2865              :                 float og2 = m_opticalGain * m_opticalGain;
    2866              :                 if( !m_loop )
    2867              :                 {
    2868              :                     MGO_BREADCRUMB;
    2869              :                     for( size_t f = 1; f < m_goptCurrent[n].f_size(); ++f )
    2870              :                     {
    2871              :                         m_olPSDs[n][f] = m_clPSDs( f, n ) / og2;
    2872              :                     }
    2873              :                 }
    2874              :                 else
    2875              :                 {
    2876              :                     MGO_BREADCRUMB;
    2877              :                     for( size_t f = 1; f < m_goptCurrent[n].f_size(); ++f )
    2878              :                     {
    2879              :                         m_olPSDs[n][f] = ( m_clPSDs( f, n ) / og2 ) / m_clXferCurrent( f, n );
    2880              :                     }
    2881              :                 }
    2882              : 
    2883              :                 MGO_BREADCRUMB;
    2884              : 
    2885              :                 m_olPSDs[n][0] = m_olPSDs[n][1];
    2886              : 
    2887              :                 bool  flagOff = false;
    2888              :                 float extrap  = 0;
    2889              : 
    2890              :                 // Calculate the noise as the 25th percentile in log10
    2891              :                 // this is to avoid spikes that make the noise too high
    2892              :                 size_t f0 = 0.5 * m_goptCurrent[n].f_size();
    2893              :                 size_t f1 = m_goptCurrent[n].f_size();
    2894              : 
    2895              :                 std::vector<float> npsd( f1 - f0 );
    2896              :                 for( size_t f = f0; f < f1; ++f )
    2897              :                 {
    2898              :                     npsd[f - f0] = log10( m_olPSDs[n][f] );
    2899              :                 }
    2900              :                 float pct = 0.25;
    2901              : 
    2902              :                 MGO_BREADCRUMB;
    2903              :                 if( n < 2 )
    2904              :                 {
    2905              :                     pct = 0.05;
    2906              :                 }
    2907              : 
    2908              :                 auto nth = npsd.begin() + pct * ( f1 - f0 );
    2909              :                 std::nth_element( npsd.begin(), nth, npsd.end() );
    2910              : 
    2911              :                 MGO_BREADCRUMB;
    2912              : 
    2913              :                 float noise = pow( 10, *nth );
    2914              :                 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    2915              :                 {
    2916              :                     m_nPSDs[n][f] = noise;
    2917              :                 }
    2918              : 
    2919              :                 if( m_extrapOL )
    2920              :                 {
    2921              :                     for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    2922              :                     {
    2923              :                         m_olPSDs[n][f] = m_olPSDs[n][f] - m_nPSDs[n][f];
    2924              :                     }
    2925              : 
    2926              :                     MGO_BREADCRUMB;
    2927              : 
    2928              :                     // Calculate an average extrapolation point referenced to 1 Hz
    2929              : 
    2930              :                     extrap   = 0;
    2931              :                     int nexp = 0;
    2932              :                     int noff = 0;
    2933              :                     for( size_t f = 1; f < 0.05 * m_freq.size(); ++f )
    2934              :                     {
    2935              :                         // This is a threshold for "too noisy"
    2936              :                         ///\todo make configurable
    2937              :                         if( m_olPSDs[n][f] <= 0.1 * m_nPSDs[n][f] )
    2938              :                         {
    2939              :                             ++noff;
    2940              :                             continue;
    2941              :                         }
    2942              :                         extrap += log10( m_olPSDs[n][f] * pow( m_freq[f] / m_freq[1], 8. / 3. ) );
    2943              :                         ++nexp;
    2944              :                     }
    2945              : 
    2946              :                     extrap = pow( 10, extrap / nexp );
    2947              : 
    2948              :                     MGO_BREADCRUMB;
    2949              :                     if( noff > 0.5 * ( 0.05 * m_freq.size() - 1 ) && n > 1 )
    2950              :                     {
    2951              :                         flagOff = true;
    2952              :                     }
    2953              :                 }
    2954              : 
    2955              :                 // flagOff = false;
    2956              : 
    2957              :                 MGO_BREADCRUMB;
    2958              : 
    2959              :                 if( flagOff )
    2960              :                 {
    2961              :                     MGO_BREADCRUMB;
    2962              :                     #pragma omp critical
    2963              :                     {
    2964              :                         ++off;
    2965              :                     }
    2966              : 
    2967              :                     for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    2968              :                     {
    2969              :                         m_olPSDs[n][f] = m_nPSDs[n][f];
    2970              :                     }
    2971              : 
    2972              :                     m_modeVarOL[n] = mx::sigproc::psdVar( m_freq, m_olPSDs[n] );
    2973              : 
    2974              :                     m_optGainSI[n] = 0;
    2975              :                     m_modeVarSI[n] = m_modeVarOL[n];
    2976              : 
    2977              :                     for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    2978              :                     {
    2979              :                         m_clXferSI( f, n ) = 1;
    2980              :                     }
    2981              : 
    2982              :                     m_timesOnSI[n] = 0;
    2983              :                 }
    2984              :                 else
    2985              :                 {
    2986              :                     MGO_BREADCRUMB;
    2987              : 
    2988              :                     if( m_extrapOL )
    2989              :                     {
    2990              :                         std::vector<float> tosmooth( m_nFreq );
    2991              : 
    2992              :                         for( size_t f = 0; f < m_nFreq; ++f )
    2993              :                         {
    2994              :                             if( m_olPSDs[n][f] < 0 )
    2995              :                             {
    2996              :                                 tosmooth[f] = extrap * pow( m_freq[1] / m_freq[f], 8. / 3. );
    2997              :                             }
    2998              :                             else
    2999              :                             {
    3000              :                                 tosmooth[f] = m_olPSDs[n][f];
    3001              :                             }
    3002              :                         }
    3003              : 
    3004              :                         std::vector<float> l10( m_nFreq ), smol( m_nFreq );
    3005              :                         std::vector<int>   smw( m_nFreq );
    3006              :                         smw[0] = 2;
    3007              :                         smw[1] = 2;
    3008              :                         l10[0] = log10( tosmooth[0] );
    3009              :                         l10[1] = log10( tosmooth[1] );
    3010              : 
    3011              :                         for( size_t f = 2; f < smw.size(); ++f )
    3012              :                         {
    3013              :                             smw[f] = 2 + static_cast<float>( f ) / 10;
    3014              :                             l10[f] = log10( tosmooth[f] );
    3015              :                         }
    3016              : 
    3017              :                         mx::math::vectorSmoothMean( smol, l10, smw );
    3018              : 
    3019              :                         for( size_t f = 0; f < m_nFreq; ++f )
    3020              :                         {
    3021              :                             smol[f] = pow( 10, smol[f] );
    3022              :                         }
    3023              : 
    3024              :                         for( size_t f = 0; f < m_nFreq; ++f )
    3025              :                         {
    3026              :                             if( m_olPSDs[n][f] < m_nPSDs[n][f] )
    3027              :                             {
    3028              :                                 m_olPSDs[n][f] = smol[f];
    3029              :                             }
    3030              :                         }
    3031              :                     }
    3032              : 
    3033              :                     MGO_BREADCRUMB;
    3034              :                     m_modeVarOL[n] = mx::sigproc::psdVar( m_freq, m_olPSDs[n] );
    3035              : 
    3036              :                     m_optGainSI[n] =
    3037              :                         m_goptSI[n].optGainOpenLoop( m_modeVarSI[n], m_olPSDs[n], m_nPSDs[n], m_gmaxSI[n], false );
    3038              : 
    3039              :                     if( ( m_modeVarSI[n] - m_modeVarOL[n] ) / m_modeVarOL[n] > -0.001 )
    3040              :                     {
    3041              :                         #pragma omp critical
    3042              :                     {
    3043              :                         ++off;
    3044              :                     }
    3045              : 
    3046              :                         MGO_BREADCRUMB;
    3047              :                         m_optGainSI[n] = 0;
    3048              :                         m_modeVarSI[n] = m_modeVarOL[n];
    3049              : 
    3050              :                         for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    3051              :                         {
    3052              :                             m_clXferSI( f, n ) = 1;
    3053              :                         }
    3054              : 
    3055              :                         m_timesOnSI[n] = 0;
    3056              :                     }
    3057              :                     else if( m_timesOnSI[n] < 5 )
    3058              :                     {
    3059              :                         #pragma omp critical
    3060              :                     {
    3061              :                         ++off;
    3062              :                     }
    3063              : 
    3064              :                         MGO_BREADCRUMB;
    3065              :                         // Would be on, but we debounce
    3066              :                         m_optGainSI[n] = 0;
    3067              :                         m_modeVarSI[n] = m_modeVarOL[n];
    3068              : 
    3069              :                         for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    3070              :                         {
    3071              :                             m_clXferSI( f, n ) = 1;
    3072              :                         }
    3073              : 
    3074              :                         ++m_timesOnSI[n];
    3075              :                     }
    3076              :                     else
    3077              :                     {
    3078              :                         MGO_BREADCRUMB;
    3079              :                         for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    3080              :                         {
    3081              :                             m_clXferSI( f, n ) = m_goptSI[n].clETF2( f, m_optGainSI[n] );
    3082              :                         }
    3083              : 
    3084              :                         ++m_timesOnSI[n];
    3085              :                     }
    3086              :                 }
    3087              : 
    3088              :                 if( m_doPCCalcs && !flagOff )
    3089              :                 {
    3090              :                     MGO_BREADCRUMB;
    3091              :                     if( m_regScale[n] == -999 || m_regCounter[n] >= m_nRegCycles )
    3092              :                     {
    3093              :                         MGO_BREADCRUMB;
    3094              :                         float min_sc;
    3095              :                         float gmax_lp = 0;
    3096              : 
    3097              :                         if( m_linPred[n].regularizeCoefficients( gmax_lp,
    3098              :                                                                  m_optGainLP[n],
    3099              :                                                                  m_modeVarLP[n],
    3100              :                                                                  min_sc,
    3101              :                                                                  m_goptLP[n],
    3102              :                                                                  m_olPSDs[n],
    3103              :                                                                  m_nPSDs[n],
    3104              :                                                                  m_Na[n] ) < 0 )
    3105              :                         {
    3106              :                             MGO_BREADCRUMB;
    3107              : 
    3108              :                             m_optGainLP[n] = 0;
    3109              :                             m_modeVarLP[n] = m_modeVarOL[n];
    3110              : 
    3111              :                             ///\todo what to do about coeffs?
    3112              :                         }
    3113              : 
    3114              :                         MGO_BREADCRUMB;
    3115              : 
    3116              :                         if( m_regScale[n] == -999 )
    3117              :                         {
    3118              :                             MGO_BREADCRUMB;
    3119              :                             m_regCounter[n] = n % m_nRegCycles;
    3120              :                         }
    3121              :                         else
    3122              :                         {
    3123              :                             MGO_BREADCRUMB;
    3124              :                             m_regCounter[n] = 0;
    3125              :                         }
    3126              : 
    3127              :                         m_regScale[n] = min_sc;
    3128              :                         m_gmaxLP[n]   = gmax_lp;
    3129              :                     }
    3130              :                     else
    3131              :                     {
    3132              :                         MGO_BREADCRUMB;
    3133              :                         // use pre-regularized version
    3134              :                         float psdReg = m_olPSDs[n][0];
    3135              :                         if( m_linPred[n].calcCoefficients(
    3136              :                                 m_olPSDs[n], m_nPSDs[n], psdReg * pow( 10, -m_regScale[n] / 10 ), m_Na[n] ) < 0 )
    3137              :                         {
    3138              :                             m_optGainLP[n] = 0;
    3139              :                             m_modeVarLP[n] = m_modeVarOL[n];
    3140              : 
    3141              :                             ///\todo what to do about coeffs?
    3142              :                         }
    3143              :                         else
    3144              :                         {
    3145              :                             m_goptLP[n].a( m_linPred[n].m_lp.m_c );
    3146              :                             m_goptLP[n].b( m_linPred[n].m_lp.m_c );
    3147              : 
    3148              :                             m_optGainLP[n] = m_goptLP[n].optGainOpenLoop(
    3149              :                                 m_modeVarLP[n], m_olPSDs[n], m_nPSDs[n], m_gmaxLP[n], false );
    3150              :                         }
    3151              :                         ++m_regCounter[n];
    3152              :                     }
    3153              : 
    3154              :                     MGO_BREADCRUMB;
    3155              : 
    3156              :                     /*if( ( m_modeVarLP[n] - m_modeVarOL[n] ) / m_modeVarOL[n] > -0.001 )
    3157              :                     {
    3158              :                         m_optGainLP[n] = 0;
    3159              :                         m_modeVarLP[n] = m_modeVarOL[n];
    3160              : 
    3161              :                         for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    3162              :                         {
    3163              :                             m_clXferLP( f, n ) = 1;
    3164              :                         }
    3165              : 
    3166              :                         m_timesOnLP[n] = 0;
    3167              :                     }
    3168              :                     else*/
    3169              :                     if( ( m_modeVarLP[n] - m_modeVarSI[n] ) / m_modeVarSI[n] > -0.001 )
    3170              :                     {
    3171              :                         #pragma omp critical
    3172              :                     {
    3173              :                         ++offLP;
    3174              :                     }
    3175              : 
    3176              : 
    3177              :                         MGO_BREADCRUMB;
    3178              :                         m_optGainLP[n] = m_optGainSI[n];
    3179              :                         m_modeVarLP[n] = m_modeVarSI[n];
    3180              : 
    3181              :                         for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    3182              :                         {
    3183              :                             m_clXferLP( f, n ) = m_clXferSI( f, n );
    3184              :                         }
    3185              : 
    3186              :                         m_timesOnLP[n] = 0;
    3187              :                     }
    3188              :                     else if( m_timesOnLP[n] < 5 )
    3189              :                     {
    3190              :                         #pragma omp critical
    3191              :                     {
    3192              :                         ++offLP;
    3193              :                     }
    3194              : 
    3195              : 
    3196              :                         MGO_BREADCRUMB;
    3197              :                         m_optGainLP[n] = m_optGainSI[n];
    3198              :                         m_modeVarLP[n] = m_modeVarSI[n];
    3199              : 
    3200              :                         for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    3201              :                         {
    3202              :                             m_clXferLP( f, n ) = m_clXferSI( f, n );
    3203              :                         }
    3204              : 
    3205              :                         ++m_timesOnLP[n];
    3206              :                     }
    3207              :                     else
    3208              :                     {
    3209              :                         MGO_BREADCRUMB;
    3210              :                         for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    3211              :                         {
    3212              :                             m_clXferLP( f, n ) = m_goptLP[n].clETF2( f, m_optGainLP[n] );
    3213              :                         }
    3214              : 
    3215              :                         ++m_timesOnLP[n];
    3216              :                     }
    3217              :                 }
    3218              :                 else
    3219              :                 {
    3220              :                     #pragma omp critical
    3221              :                     {
    3222              :                         ++offLP;
    3223              :                     }
    3224              : 
    3225              :                     MGO_BREADCRUMB;
    3226              :                     m_optGainLP[n] = 0;
    3227              : 
    3228              :                     ++m_regCounter[n];
    3229              : 
    3230              :                     for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
    3231              :                     {
    3232              :                         m_clXferLP( f, n ) = 1;
    3233              :                     }
    3234              : 
    3235              :                     m_timesOnLP[n] = 0;
    3236              :                 }
    3237              : 
    3238              :                 MGO_BREADCRUMB;
    3239              :             }
    3240              : 
    3241              :             MGO_BREADCRUMB;
    3242              : 
    3243            0 :             m_modesOnSI = m_nModes - off;
    3244            0 :             m_modesOnLP = m_nModes - offLP;
    3245              : 
    3246              : 
    3247              : 
    3248              : 
    3249            0 :             if( m_updating )
    3250              :             {
    3251            0 :                 continue; // don't break b/c of omp
    3252              :             }
    3253              : 
    3254            0 :             timePointT t1 = std::chrono::steady_clock::now();
    3255            0 :             durationT  dt = t1 - t0;
    3256              : 
    3257            0 :             std::cerr << "Optimization took " << dt.count() << " seconds\n";
    3258              : 
    3259              :             /*float totVar = 0;
    3260              :             for( size_t n = 0; n < m_modeVarSI.size(); ++n )
    3261              :             {
    3262              :                 totVar += m_modeVarSI[n];
    3263              :             }*/
    3264              : 
    3265              :             // std::cerr << "total variance: " << totVar << '\n';
    3266              : 
    3267            0 :             float *f      = m_optGainStream->array.F;
    3268            0 :             float *fSI    = m_optGainSIStream->array.F;
    3269            0 :             float *fmaxSI = m_maxGainSIStream->array.F;
    3270            0 :             float *fLP    = m_optGainLPStream->array.F;
    3271            0 :             float *fmaxLP = m_optGainLPStream->array.F;
    3272              : 
    3273            0 :             mx::improc::eigenMap<float> mvs( m_modevarStream->array.F, 3, m_modeVarSI.size() );
    3274              : 
    3275            0 :             m_optGainStream->md->write   = 1;
    3276            0 :             m_optGainSIStream->md->write = 1;
    3277            0 :             m_maxGainSIStream->md->write = 1;
    3278            0 :             m_optGainLPStream->md->write = 1;
    3279            0 :             m_maxGainLPStream->md->write = 1;
    3280            0 :             m_modevarStream->md->write   = 1;
    3281              : 
    3282            0 :             for( size_t n = 0; n < m_optGainSI.size(); ++n )
    3283              :             {
    3284              :                 // if( m_timesOnSI[n] > 5 )
    3285              :                 {
    3286            0 :                     f[n]      = ( m_gainCalFacts[n] * m_optGainSI[n] / m_gainCals[n] ) / m_opticalGain;
    3287            0 :                     fSI[n]    = f[n];
    3288            0 :                     fmaxSI[n] = ( m_gainCalFacts[n] * m_gmaxSI[n] / m_gainCals[n] ) / m_opticalGain;
    3289              :                 }
    3290              : 
    3291              :                 // if( m_timesOnLP[n] > 5 )
    3292              :                 {
    3293            0 :                     fLP[n]    = ( m_gainCalFacts[n] * m_optGainLP[n] / m_gainCals[n] ) / m_opticalGain;
    3294            0 :                     fmaxLP[n] = ( m_gainCalFacts[n] * m_gmaxLP[n] / m_gainCals[n] ) / m_opticalGain;
    3295              :                 }
    3296              : 
    3297            0 :                 mvs( 0, n ) = m_modeVarOL[n];
    3298            0 :                 mvs( 1, n ) = m_modeVarSI[n];
    3299            0 :                 mvs( 2, n ) = m_modeVarLP[n];
    3300              :             }
    3301              : 
    3302            0 :             ImageStreamIO_UpdateIm( m_optGainStream );
    3303            0 :             ImageStreamIO_UpdateIm( m_optGainSIStream );
    3304            0 :             ImageStreamIO_UpdateIm( m_maxGainSIStream );
    3305            0 :             ImageStreamIO_UpdateIm( m_optGainLPStream );
    3306            0 :             ImageStreamIO_UpdateIm( m_maxGainLPStream );
    3307            0 :             ImageStreamIO_UpdateIm( m_modevarStream );
    3308              : 
    3309            0 :             if( m_autoUpdate || m_updateOnce || m_dump )
    3310              :             {
    3311            0 :                 float *f = gainFactShmimMonitorT::m_imageStream.array.F;
    3312              : 
    3313            0 :                 gainFactShmimMonitorT::m_imageStream.md->write = 1;
    3314            0 :                 if( m_dump )
    3315              :                 {
    3316            0 :                     for( size_t n = 0; n < m_nModes; ++n )
    3317              :                     {
    3318              :                         // if( m_timesOnSI[n] > 5 )
    3319              :                         {
    3320            0 :                             f[n] = ( m_gainCalFacts[n] * m_optGainSI[n] / m_gainCals[n] ) / m_opticalGain;
    3321              :                         }
    3322              :                     }
    3323              :                 }
    3324              :                 else
    3325              :                 {
    3326            0 :                     for( size_t n = 0; n < m_nModes; ++n )
    3327              :                     {
    3328              :                         // if( m_timesOnSI[n] > 5 )
    3329              :                         {
    3330            0 :                             f[n] = f[n] + m_gainGain *
    3331            0 :                                               ( ( m_gainCalFacts[n] * m_optGainSI[n] / m_gainCals[n] ) / m_opticalGain -
    3332            0 :                                                 f[n] );
    3333              :                         }
    3334              :                     }
    3335              :                 }
    3336              : 
    3337            0 :                 ImageStreamIO_UpdateIm( &( gainFactShmimMonitorT::m_imageStream ) );
    3338              : 
    3339            0 :                 if( m_doPCCalcs )
    3340              :                 {
    3341            0 :                     float *fpc = pcGainFactShmimMonitorT::m_imageStream.array.F;
    3342            0 :                     float *fa  = acoeffShmimMonitorT::m_imageStream.array.F;
    3343            0 :                     float *fb  = bcoeffShmimMonitorT::m_imageStream.array.F;
    3344              : 
    3345            0 :                     pcGainFactShmimMonitorT::m_imageStream.md->write = 1;
    3346            0 :                     acoeffShmimMonitorT::m_imageStream.md->write     = 1;
    3347            0 :                     bcoeffShmimMonitorT::m_imageStream.md->write     = 1;
    3348              : 
    3349            0 :                     if( m_dump )
    3350              :                     {
    3351            0 :                         for( size_t n = 0; n < m_optGainLP.size(); ++n )
    3352              :                         {
    3353              :                             // if( m_timesOnLP[n] > 5 )
    3354              :                             {
    3355            0 :                                 fpc[n] = ( m_gainCalFacts[n] * m_optGainLP[n] / m_gainCals[n] ) / m_opticalGain;
    3356              : 
    3357              :                                 // To be safe we treat this as if Na and Nb can be different, but they can't be.
    3358            0 :                                 fa[n] = m_Na[n];
    3359            0 :                                 fb[n] = m_Nb[n];
    3360            0 :                                 for( uint32_t k = 0; k < m_Na[n]; ++k )
    3361              :                                 {
    3362            0 :                                     fa[1 + k] = m_goptLP[n].a()[k];
    3363              :                                 }
    3364            0 :                                 for( uint32_t k = m_Na[n]; k < acoeffShmimMonitorT::m_width - 1; ++k )
    3365              :                                 {
    3366            0 :                                     fa[1 + k] = 0;
    3367              :                                 }
    3368              : 
    3369            0 :                                 for( uint32_t k = 0; k < m_Nb[n]; ++k )
    3370              :                                 {
    3371            0 :                                     fb[1 + k] = m_goptLP[n].b()[k];
    3372              :                                 }
    3373            0 :                                 for( uint32_t k = m_Nb[n]; k < bcoeffShmimMonitorT::m_width - 1; ++k )
    3374              :                                 {
    3375            0 :                                     fb[1 + k] = 0;
    3376              :                                 }
    3377              :                             }
    3378              :                         }
    3379              :                     }
    3380              :                     else
    3381              :                     {
    3382            0 :                         for( size_t n = 0; n < m_optGainSI.size(); ++n )
    3383              :                         {
    3384              :                             // if( m_timesOnLP[n] > 5 )
    3385              :                             {
    3386            0 :                                 fpc[n] = fpc[n] +
    3387            0 :                                          m_gainGain *
    3388            0 :                                              ( ( m_gainCalFacts[n] * m_optGainLP[n] / m_gainCals[n] ) / m_opticalGain -
    3389            0 :                                                fpc[n] );
    3390              : 
    3391              :                                 // To be safe we treat this as if Na and Nb can be different, but they can't be.
    3392            0 :                                 fa[n] = m_Na[n];
    3393            0 :                                 fb[n] = m_Nb[n];
    3394            0 :                                 for( uint32_t k = 0; k < m_Na[n]; ++k )
    3395              :                                 {
    3396            0 :                                     fa[1 + k] = fa[1 + k] + m_gainGain * ( m_goptLP[n].a()[k] - fa[1 + k] );
    3397              :                                 }
    3398            0 :                                 for( uint32_t k = m_Na[n]; k < acoeffShmimMonitorT::m_width - 1; ++k )
    3399              :                                 {
    3400            0 :                                     fa[1 + k] = 0;
    3401              :                                 }
    3402              : 
    3403            0 :                                 for( uint32_t k = 0; k < m_Nb[n]; ++k )
    3404              :                                 {
    3405            0 :                                     fb[1 + k] = fb[1 + k] + m_gainGain * ( m_goptLP[n].b()[k] - fb[1 + k] );
    3406              :                                 }
    3407            0 :                                 for( uint32_t k = m_Nb[n]; k < bcoeffShmimMonitorT::m_width - 1; ++k )
    3408              :                                 {
    3409            0 :                                     fb[1 + k] = 0;
    3410              :                                 }
    3411              :                             }
    3412              :                         }
    3413              :                     }
    3414              : 
    3415            0 :                     ImageStreamIO_UpdateIm( &( pcGainFactShmimMonitorT::m_imageStream ) );
    3416            0 :                     ImageStreamIO_UpdateIm( &( acoeffShmimMonitorT::m_imageStream ) );
    3417            0 :                     ImageStreamIO_UpdateIm( &( bcoeffShmimMonitorT::m_imageStream ) );
    3418              :                 }
    3419              : 
    3420            0 :                 if( m_dump )
    3421              :                 {
    3422            0 :                     log<text_log>( "gains updated by dump", logPrio::LOG_NOTICE );
    3423            0 :                     m_dump = false;
    3424              :                 }
    3425            0 :                 else if( m_updateOnce && !m_autoUpdate )
    3426              :                 {
    3427            0 :                     log<text_log>( "gains updated once", logPrio::LOG_NOTICE );
    3428              :                 }
    3429              : 
    3430            0 :                 m_updateOnce = false;
    3431              :             }
    3432              : 
    3433            0 :             if( m_loop & m_autoUpdate )
    3434              :             {
    3435            0 :                 m_sinceChange = -1;
    3436              :             }
    3437              : 
    3438              :             // Update OL PSDs and Transfer Functions
    3439            0 :             m_olPSDStream->md->write         = 1;
    3440            0 :             m_noisePSDStream->md->write      = 1;
    3441            0 :             m_clXferCurrentStream->md->write = 1;
    3442            0 :             m_clXferSIStream->md->write      = 1;
    3443            0 :             m_clXferLPStream->md->write      = 1;
    3444              : 
    3445            0 :             for( size_t q = 0; q < m_olPSDs.size(); ++q )
    3446              :             {
    3447            0 :                 memcpy( m_olPSDStream->array.F + q * m_olPSDs[0].size(),
    3448            0 :                         m_olPSDs[q].data(),
    3449            0 :                         m_olPSDs[0].size() * sizeof( float ) );
    3450              : 
    3451              :                 // m_noisePSDStream->array.F[q] = m_nPSDs[q][0];
    3452            0 :                 memcpy( m_noisePSDStream->array.F + q * m_nPSDs[0].size(),
    3453            0 :                         m_nPSDs[q].data(),
    3454            0 :                         m_nPSDs[0].size() * sizeof( float ) );
    3455              :             }
    3456              : 
    3457            0 :             memcpy( m_clXferCurrentStream->array.F,
    3458            0 :                     m_clXferCurrent.data(),
    3459            0 :                     m_clXferCurrent.rows() * m_clXferCurrent.cols() * sizeof( float ) );
    3460            0 :             memcpy(
    3461            0 :                 m_clXferSIStream->array.F, m_clXferSI.data(), m_clXferSI.rows() * m_clXferSI.cols() * sizeof( float ) );
    3462            0 :             memcpy(
    3463            0 :                 m_clXferLPStream->array.F, m_clXferLP.data(), m_clXferLP.rows() * m_clXferLP.cols() * sizeof( float ) );
    3464              : 
    3465            0 :             ImageStreamIO_UpdateIm( m_olPSDStream );
    3466            0 :             ImageStreamIO_UpdateIm( m_noisePSDStream );
    3467            0 :             ImageStreamIO_UpdateIm( m_clXferCurrentStream );
    3468            0 :             ImageStreamIO_UpdateIm( m_clXferSIStream );
    3469            0 :             ImageStreamIO_UpdateIm( m_clXferLPStream );
    3470            0 :         }
    3471              :         else
    3472              :         {
    3473              :             /* Check for why we timed out */
    3474              :             /* ETIMEDOUT just means keep waiting */
    3475            0 :             if( errno == ETIMEDOUT )
    3476              :             {
    3477              :                 // Could Update gopts if needed (requires size checks and requires mutex lock)
    3478              :                 // Probably not worth it for pred. control anyway.
    3479            0 :                 continue;
    3480              :             }
    3481              : 
    3482              :             /* EINTER probably indicates time to shutdown, loop wil exit if m_shutdown is set */
    3483            0 :             if( errno == EINTR )
    3484              :             {
    3485            0 :                 continue;
    3486              :             }
    3487              : 
    3488              :             /*Otherwise, report an error.*/
    3489            0 :             log<software_error>( { __FILE__, __LINE__, errno, "sem_timedwait" } );
    3490            0 :             break;
    3491              :         }
    3492              :     }
    3493              : }
    3494              : 
    3495            0 : INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_autoUpdate )( const pcf::IndiProperty &ipRecv )
    3496              : {
    3497            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_autoUpdate, ipRecv );
    3498              : 
    3499            0 :     if( ipRecv.find( "toggle" ) )
    3500              :     {
    3501            0 :         if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
    3502              :         {
    3503            0 :             if( !m_autoUpdate )
    3504              :             {
    3505            0 :                 log<text_log>( "updating gains", logPrio::LOG_NOTICE );
    3506              :             }
    3507            0 :             m_autoUpdate = true;
    3508              :         }
    3509              :         else
    3510              :         {
    3511            0 :             if( m_autoUpdate )
    3512              :             {
    3513            0 :                 log<text_log>( "stopped updating gains", logPrio::LOG_NOTICE );
    3514              :             }
    3515            0 :             m_autoUpdate = false;
    3516              :         }
    3517              :     }
    3518              : 
    3519            0 :     return 0;
    3520              : }
    3521              : 
    3522            0 : INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_updateOnce )( const pcf::IndiProperty &ipRecv )
    3523              : {
    3524            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_updateOnce, ipRecv );
    3525              : 
    3526            0 :     if( ipRecv.find( "request" ) )
    3527              :     {
    3528            0 :         if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
    3529              :         {
    3530            0 :             m_updateOnce = true;
    3531              :         }
    3532              :         else
    3533              :         {
    3534            0 :             m_updateOnce = false;
    3535              :         }
    3536              :     }
    3537              : 
    3538            0 :     return 0;
    3539              : }
    3540              : 
    3541            0 : INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_dump )( const pcf::IndiProperty &ipRecv )
    3542              : {
    3543            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_dump, ipRecv );
    3544              : 
    3545            0 :     if( ipRecv.find( "request" ) )
    3546              :     {
    3547            0 :         if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
    3548              :         {
    3549            0 :             m_dump = true;
    3550              :         }
    3551              :         else
    3552              :         {
    3553            0 :             m_dump = false;
    3554              :         }
    3555              :     }
    3556              : 
    3557            0 :     return 0;
    3558              : }
    3559              : 
    3560            0 : INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_opticalGain )( const pcf::IndiProperty &ipRecv )
    3561              : {
    3562            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_opticalGain, ipRecv );
    3563              : 
    3564              :     float target;
    3565            0 :     if( indiTargetUpdate( m_indiP_opticalGain, target, ipRecv, true ) < 0 )
    3566              :     {
    3567            0 :         log<software_error>( { __FILE__, __LINE__ } );
    3568            0 :         return -1;
    3569              :     }
    3570              : 
    3571            0 :     m_opticalGain = target;
    3572              : 
    3573            0 :     return 0;
    3574              : }
    3575              : 
    3576            0 : INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_opticalGainUpdate )( const pcf::IndiProperty &ipRecv )
    3577              : {
    3578            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_opticalGainUpdate, ipRecv );
    3579              : 
    3580            0 :     if(ipRecv.find("toggle"))
    3581              :     {
    3582            0 :         if(ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
    3583              :         {
    3584            0 :             m_opticalGainUpdate = false;
    3585              :         }
    3586              :         else
    3587              :         {
    3588            0 :             m_opticalGainUpdate = true;
    3589              : 
    3590            0 :             if(m_opticalGainSource > 0 && m_opticalGainSource < 1)
    3591              :             {
    3592            0 :                 m_opticalGain = m_opticalGainSource;
    3593              :             }
    3594              :         }
    3595              :     }
    3596              : 
    3597            0 :     return 0;
    3598              : }
    3599              : 
    3600            0 : INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_opticalGainSource )( const pcf::IndiProperty &ipRecv )
    3601              : {
    3602            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_opticalGainSource, ipRecv );
    3603              : 
    3604            0 :     if( ipRecv.find( m_opticalGainElement ) )
    3605              :     {
    3606            0 :         float opticalg = ipRecv[m_opticalGainElement].get<float>();
    3607              : 
    3608            0 :         opticalg = (floor(opticalg * 100 + 0.5))/100.;
    3609              : 
    3610            0 :         if(opticalg > 0 && opticalg < 1)
    3611              :         {
    3612            0 :             m_opticalGainSource = opticalg;
    3613              :         }
    3614              : 
    3615            0 :         if(m_opticalGainUpdate)
    3616              :         {
    3617            0 :             m_opticalGain = m_opticalGainSource;
    3618              :         }
    3619              :     }
    3620            0 :     return 0;
    3621              : }
    3622              : 
    3623            0 : INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_gainGain )( const pcf::IndiProperty &ipRecv )
    3624              : {
    3625            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_gainGain, ipRecv );
    3626              : 
    3627              :     float target;
    3628            0 :     if( indiTargetUpdate( m_indiP_gainGain, target, ipRecv, true ) < 0 )
    3629              :     {
    3630            0 :         log<software_error>( { __FILE__, __LINE__ } );
    3631            0 :         return -1;
    3632              :     }
    3633              : 
    3634            0 :     m_gainGain = target;
    3635              : 
    3636            0 :     return 0;
    3637              : }
    3638              : 
    3639            0 : INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_emg )( const pcf::IndiProperty &ipRecv )
    3640              : {
    3641            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_emg, ipRecv );
    3642              : 
    3643            0 :     if( ipRecv.find( "current" ) )
    3644              :     {
    3645            0 :         float emg = ipRecv["current"].get<float>();
    3646              : 
    3647            0 :         if( emg != m_emg )
    3648              :         {
    3649            0 :             m_emg = emg;
    3650            0 :             std::cerr << "Got EMG: " << m_emg << '\n';
    3651              :         }
    3652              :     }
    3653            0 :     return 0;
    3654              : }
    3655              : 
    3656            0 : INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_psdTime )( const pcf::IndiProperty &ipRecv )
    3657              : {
    3658            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_psdTime, ipRecv );
    3659              : 
    3660            0 :     if( ipRecv.find( "current" ) )
    3661              :     {
    3662            0 :         float psdTime = ipRecv["current"].get<float>();
    3663              : 
    3664            0 :         if( psdTime != m_psdTime )
    3665              :         {
    3666            0 :             m_updating = true;
    3667            0 :             std::lock_guard<std::mutex> lock( m_goptMutex );
    3668            0 :             m_updating = true;
    3669              : 
    3670            0 :             m_psdTime = psdTime;
    3671              : 
    3672            0 :             m_sinceChange = -1;
    3673            0 :             m_updating    = false;
    3674              : 
    3675            0 :             std::cerr << "Got psdTime: " << m_psdTime << '\n';
    3676            0 :         }
    3677              :     }
    3678            0 :     return 0;
    3679              : }
    3680              : 
    3681            0 : INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_psdAvgTime )( const pcf::IndiProperty &ipRecv )
    3682              : {
    3683            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_psdAvgTime, ipRecv );
    3684              : 
    3685            0 :     if( ipRecv.find( "current" ) )
    3686              :     {
    3687            0 :         float psdAvgTime = ipRecv["current"].get<float>();
    3688              : 
    3689            0 :         if( psdAvgTime != m_psdAvgTime )
    3690              :         {
    3691            0 :             m_updating = true;
    3692            0 :             std::lock_guard<std::mutex> lock( m_goptMutex );
    3693            0 :             m_updating = true;
    3694              : 
    3695            0 :             m_psdAvgTime = psdAvgTime;
    3696              : 
    3697            0 :             m_sinceChange = -1;
    3698            0 :             m_updating    = false;
    3699              : 
    3700            0 :             std::cerr << "Got psdAvgTime: " << m_psdAvgTime << '\n';
    3701            0 :         }
    3702              :     }
    3703              : 
    3704            0 :     return 0;
    3705              : }
    3706              : 
    3707            0 : INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_loop )( const pcf::IndiProperty &ipRecv )
    3708              : {
    3709            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_loop, ipRecv );
    3710              : 
    3711            0 :     if( ipRecv.find( "toggle" ) )
    3712              :     {
    3713              :         bool state;
    3714              : 
    3715            0 :         if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
    3716              :         {
    3717            0 :             state = true;
    3718              :         }
    3719              :         else
    3720              :         {
    3721            0 :             state = false;
    3722              :         }
    3723              : 
    3724            0 :         if( state != m_loop )
    3725              :         {
    3726            0 :             m_updating = true;
    3727            0 :             std::lock_guard<std::mutex> lock( m_goptMutex );
    3728            0 :             m_updating = true;
    3729              : 
    3730            0 :             m_loop = state;
    3731              : 
    3732            0 :             if( !m_loop )
    3733              :             {
    3734            0 :                 m_autoUpdate = false;
    3735            0 :                 m_dump       = false;
    3736              :             }
    3737              : 
    3738            0 :             m_sinceChange = -1;
    3739            0 :             m_updating    = false;
    3740            0 :             std::cerr << "Got loop: " << m_loop << '\n';
    3741            0 :         }
    3742              :     }
    3743              : 
    3744            0 :     return 0;
    3745              : }
    3746              : 
    3747            0 : INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_siGain )( const pcf::IndiProperty &ipRecv )
    3748              : {
    3749            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_siGain, ipRecv );
    3750              : 
    3751            0 :     if( ipRecv.find( "current" ) )
    3752              :     {
    3753            0 :         float gain = ipRecv["current"].get<float>();
    3754              : 
    3755            0 :         if( gain != m_gain && !m_pcOn )
    3756              :         {
    3757            0 :             m_updating = true;
    3758            0 :             std::lock_guard<std::mutex> lock( m_goptMutex );
    3759            0 :             m_updating = true;
    3760              : 
    3761            0 :             m_gain = gain;
    3762              : 
    3763            0 :             if( m_loop )
    3764              :             {
    3765            0 :                 m_sinceChange = -1;
    3766              :             }
    3767              : 
    3768            0 :             m_updating = false;
    3769              : 
    3770            0 :             std::cerr << "Got gain: " << m_gain << '\n';
    3771            0 :         }
    3772              :         else
    3773              :         {
    3774            0 :             m_gain = gain; // for the m_pcOn case
    3775              :         }
    3776              :     }
    3777              : 
    3778            0 :     return 0;
    3779              : }
    3780              : 
    3781            0 : INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_siMult )( const pcf::IndiProperty &ipRecv )
    3782              : {
    3783            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_siMult, ipRecv );
    3784              : 
    3785            0 :     if( ipRecv.find( "current" ) )
    3786              :     {
    3787            0 :         float mc = ipRecv["current"].get<float>();
    3788              : 
    3789            0 :         if( mc != m_mult && !m_pcOn )
    3790              :         {
    3791            0 :             m_updating = true;
    3792            0 :             std::lock_guard<std::mutex> lock( m_goptMutex );
    3793            0 :             m_updating = true;
    3794              : 
    3795            0 :             m_mult = mc;
    3796              : 
    3797            0 :             if( m_loop )
    3798              :             {
    3799            0 :                 m_sinceChange = -1;
    3800              :             }
    3801              : 
    3802            0 :             m_goptUpdated = true;
    3803            0 :             m_updating    = false;
    3804            0 :             std::cerr << "Got mc: " << m_mult << '\n';
    3805            0 :         }
    3806              :         else
    3807              :         {
    3808            0 :             m_mult = mc; // for the m_pcOn case
    3809              :         }
    3810              :     }
    3811              : 
    3812            0 :     return 0;
    3813              : }
    3814              : 
    3815            0 : INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_pcGain )( const pcf::IndiProperty &ipRecv )
    3816              : {
    3817            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_pcGain, ipRecv );
    3818              : 
    3819            0 :     if( ipRecv.find( "current" ) )
    3820              :     {
    3821            0 :         float gain = ipRecv["current"].get<float>();
    3822              : 
    3823            0 :         if( gain != m_pcGain && m_pcOn )
    3824              :         {
    3825            0 :             m_updating = true;
    3826            0 :             std::lock_guard<std::mutex> lock( m_goptMutex );
    3827            0 :             m_updating = true;
    3828              : 
    3829            0 :             m_pcGain = gain;
    3830              : 
    3831            0 :             if( m_loop )
    3832              :             {
    3833            0 :                 m_sinceChange = -1;
    3834              :             }
    3835              : 
    3836            0 :             m_updating = false;
    3837              : 
    3838            0 :             std::cerr << "Got pc gain: " << m_pcGain << '\n';
    3839            0 :         }
    3840              :         else
    3841              :         {
    3842            0 :             m_pcGain = gain; // for the !m_pcOn case
    3843              :         }
    3844              :     }
    3845              : 
    3846            0 :     return 0;
    3847              : }
    3848              : 
    3849            0 : INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_pcMult )( const pcf::IndiProperty &ipRecv )
    3850              : {
    3851            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_pcMult, ipRecv );
    3852              : 
    3853            0 :     if( ipRecv.find( "current" ) )
    3854              :     {
    3855            0 :         float mc = ipRecv["current"].get<float>();
    3856              : 
    3857            0 :         if( mc != m_pcMult && m_pcOn )
    3858              :         {
    3859            0 :             m_updating = true;
    3860            0 :             std::lock_guard<std::mutex> lock( m_goptMutex );
    3861            0 :             m_updating = true;
    3862              : 
    3863            0 :             m_pcMult = mc;
    3864              : 
    3865            0 :             if( m_loop )
    3866              :             {
    3867            0 :                 m_sinceChange = -1;
    3868              :             }
    3869              : 
    3870            0 :             m_pcgoptUpdated = true;
    3871            0 :             m_updating      = false;
    3872            0 :             std::cerr << "Got pc mc: " << m_pcMult << '\n';
    3873            0 :         }
    3874              :         else
    3875              :         {
    3876            0 :             m_pcMult = mc; // for the !m_pcOn case
    3877              :         }
    3878              :     }
    3879              : 
    3880            0 :     return 0;
    3881              : }
    3882              : 
    3883            0 : INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_pcOn )( const pcf::IndiProperty &ipRecv )
    3884              : {
    3885            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_pcOn, ipRecv );
    3886              : 
    3887            0 :     if( ipRecv.find( "toggle" ) )
    3888              :     {
    3889              :         bool state;
    3890              : 
    3891            0 :         if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
    3892              :         {
    3893            0 :             state = true;
    3894              :         }
    3895              :         else
    3896              :         {
    3897            0 :             state = false;
    3898              :         }
    3899              : 
    3900            0 :         if( state != m_pcOn )
    3901              :         {
    3902            0 :             m_updating = true;
    3903            0 :             std::lock_guard<std::mutex> lock( m_goptMutex );
    3904            0 :             m_updating = true;
    3905              : 
    3906            0 :             m_pcOn = state;
    3907              : 
    3908            0 :             m_sinceChange = -1;
    3909            0 :             m_updating    = false;
    3910            0 :             std::cerr << "Got pcOn: " << std::boolalpha << m_pcOn << '\n';
    3911            0 :         }
    3912              :     }
    3913              : 
    3914            0 :     return 0;
    3915              : }
    3916              : 
    3917            0 : INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapOL )( const pcf::IndiProperty &ipRecv )
    3918              : {
    3919            0 :     INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapOL, ipRecv );
    3920              : 
    3921            0 :     if( ipRecv.find( "toggle" ) )
    3922              :     {
    3923              :         int ext;
    3924              : 
    3925            0 :         if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
    3926              :         {
    3927            0 :             ext = true;
    3928              :         }
    3929              :         else
    3930              :         {
    3931            0 :             ext = false;
    3932              :         }
    3933              : 
    3934            0 :         if( ext != m_extrapOL )
    3935              :         {
    3936            0 :             m_updating = true;
    3937            0 :             std::lock_guard<std::mutex> lock( m_goptMutex );
    3938            0 :             m_updating = true;
    3939              : 
    3940            0 :             m_extrapOL = ext;
    3941              : 
    3942            0 :             m_sinceChange = -1;
    3943            0 :             m_updating    = false;
    3944            0 :             std::cerr << "Got extrap: " << m_extrapOL << '\n';
    3945            0 :         }
    3946              :     }
    3947              : 
    3948            0 :     return 0;
    3949              : }
    3950              : } // namespace app
    3951              : } // namespace MagAOX
    3952              : 
    3953              : #endif // modalGainOpt_hpp
        

Generated by: LCOV version 2.0-1