13#include <mx/improc/eigenCube.hpp>
14#include <mx/improc/eigenImage.hpp>
15#include <mx/sigproc/gramSchmidt.hpp>
16#include <mx/math/templateBLAS.hpp>
18#include "../../libMagAOX/libMagAOX.hpp"
19#include "../../magaox_git_version.h"
21#include <mx/math/cuda/cudaPtr.hpp>
22#include <mx/math/cuda/cublasHandle.hpp>
23#include <mx/math/cuda/templateCublas.hpp>
24#include <mx/math/eigenLapack.hpp>
25#include <mx/sigproc/basisUtils2D.hpp>
351 config.add(
"recon.loopNumber",
359 "The loop number. Default is 1 as in aol1." );
361 config.add(
"recon.respMPath",
369 "Optional response matrix. If set then CM modes are converted by this response." );
371 config.add(
"recon.numModes",
379 "Number of modes to reconstruct. If 0 (default) all modes in CM are used." );
381 config.add(
"recon.inverseNumModes",
383 "recon.inverseNumModes",
389 "Number of modes to use for pseudo-inverse truncation. If 0 (default) all modes are used." );
391 config.add(
"recon.fpsSource",
399 "Device name for getting fps of the loop. This device should have *.fps.current. "
400 "Default is camwfs" );
402 config.add(
"recon.gpuIndex",
410 "Index of the GPU to use for calculations. Default is 0." );
412 config.add(
"recon.useGPU",
420 "Flag controlling whether the GPU is used for calculations. Default is false." );
494 mx::fits::fitsFile<float>
ff;
578 "[{}] {}\nNOT USING GPU",
587 std::string
msg = std::format(
"CUDA: found {} devices\n",
deviceCount );
592 msg +=
" greater than devicecntMax\n";
596 msg +=
" less than zero\n";
601 msg +=
" no devices found!\nNOT USING GPU";
615 msg += std::format(
"cudaGetDeviceProperties returned error: "
616 "[{}] {}\nNOT USING GPU",
630 msg += std::format(
"cudaGetDeviceAttribute returned error: "
631 "[{}] {}\nNOT USING GPU",
640 msg += std::format(
" Device {} / {} [ {} ] has compute capability {}.{}.\n",
647 msg += std::format(
" Total amount of global memory: {} MBytes\n",
648 (
float)
deviceProp.totalGlobalMem / 1048576.0f );
650 msg += std::format(
" Multiprocessors: {}\n",
deviceProp.multiProcessorCount );
667 msg += std::format(
"cudaSetDevice returned error: "
668 "[{}] {}\nNOT USING GPU",
683 msg += std::format(
"cublasHandle create returned error: "
684 "[{}] {}\nNOT USING GPU",
693 msg +=
" cuBLAS initialized";
723 std::cerr <<
"modes not ready\n";
749 mx::sys::milliSleep( 1000 );
781 mx::sys::milliSleep( 1000 );
786 mx::improc::eigenCube<realT>
tmpc;
794 for(
int p = 0; p <
tmpc.planes(); ++p )
810 mx::fits::fitsFile<float>
ff;
842 std::cerr <<
"PInv: " <<
m_PInv.rows() <<
' ' <<
m_PInv.cols() <<
'\n';
844 mx::fits::fitsFile<float>
ff;
847 log<text_log>( std::format(
"Inverted CMmodesDM. Rejected {} "
848 "of {} modes, condition numer = {}",
855 std::cerr <<
"modes ready\n";
863 std::cerr <<
"mask not ready\n";
887 mx::sys::milliSleep( 1000 );
912 std::cerr <<
n <<
' ' <<
nmax <<
'\n';
914 std::cerr <<
"Got mask of size " <<
m_mask.rows() <<
" x " <<
m_mask.cols() <<
" with " <<
m_maskIDX.size()
915 <<
" good pixels.\n";
918 std::cerr <<
"mask ready\n";
926 std::cerr <<
"command not ready\n";
934 mx::sys::milliSleep( 1000 );
942 mx::sys::milliSleep( 1000 );
975 if(
ec != mx::error_t::noerror )
978 "error uploading PInv to GPU: [{}] {}", mx::errorName(
ec ), mx::errorMessage(
ec ) ) } );
982 if(
ec != mx::error_t::noerror )
985 "error allocating command on GPU: [{}] {}", mx::errorName(
ec ), mx::errorMessage(
ec ) ) } );
989 if(
ec != mx::error_t::noerror )
992 "error allocating modevals on GPU: [{}] {}", mx::errorName(
ec ), mx::errorMessage(
ec ) ) } );
1003 std::cerr <<
"command ready\n";
1037 if(
ec != mx::error_t::noerror )
1040 "error uploading command to GPU: [{}] {}", mx::errorName(
ec ), mx::errorMessage(
ec ) ) } );
1061 return log<
software_error, -1>( { std::format(
"error downloading modevals from GPU: [{}] {}",
1068 if(
ec != mx::error_t::noerror )
1071 "error downloading modevals from GPU: [{}] {}", mx::errorName(
ec ), mx::errorMessage(
ec ) ) } );
1116 mx::sys::milliSleep( 100 );
1182 ". Source process will need to be restarted." } );
1217 std::cerr <<
"startAcquisition\n";
1275 if(
ipRecv.find(
"current" ) !=
true )
1280 std::lock_guard<std::mutex> guard( m_indiMutex );
1282 realT fps =
ipRecv[
"current"].get<
float>();
1297 if(
ipRecv.find(
"toggle" ) !=
true )
1302 std::lock_guard<std::mutex> guard( m_indiMutex );
1304 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On )
1308 updateSwitchIfChanged( m_indiP_writeDMf,
"toggle", pcf::IndiElement::On );
1314 updateSwitchIfChanged( m_indiP_writeDMf,
"toggle", pcf::IndiElement::Off );
The base-class for XWCTk applications.
stateCodes::stateCodeT state()
Get the current state code.
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI switch element value if it has changed.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
int createROIndiNumber(pcf::IndiProperty &prop, const std::string &propName, const std::string &propLabel="", const std::string &propGroup="")
Create a ReadOnly INDI Number property.
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
std::mutex m_indiMutex
Mutex for locking INDI communications.
timespec m_currImageTimestamp
The timestamp of the current image.
uint32_t m_width
The width of the image, once deinterlaced etc.
int recordFGTimings(bool force=false)
bool m_ownShmim
Flag controlling if the shmim is owned. If true it will be destroyed as needed.
uint8_t m_dataType
The ImageStreamIO type code.
bool m_reconfig
Flag to set if a camera reconfiguration requires a framegrabber reset.
ino_t m_inode
The inode of the image stream file.
IMAGE * m_imageStream
The ImageStreamIO shared memory buffer.
uint32_t m_height
The height of the image, once deinterlaced etc.
uint32_t m_depth
The depth of the circular buffer in the stream.
uint32_t m_width
The width of the images in the stream.
uint32_t m_height
The height of the images in the stream.
bool m_restart
Flag indicating tha the shared memory should be reinitialized.
std::atomic< bool > m_updated
Flag indicating that the mode vals have been updated.
std::atomic< bool > m_fgWaiting
Flag indicating that the FG thread is waiting for the command thread.
int m_loopNumber
The loop number. Default is 1 as in aol1.
virtual int appLogic()
Implementation of the FSM for dmRecon.
mx::improc::eigenImage< realT > m_PInv
The pseudo-inverse.
std::atomic< bool > m_dmModesReady
Flag indicating that the DM modes are ready for processing.
float realT
Floating point type in which to do all calculations.
std::atomic< bool > m_commandReady
Flag indicating that all sizes match and arrays are ready for processing.
mx::improc::milkImage< float > m_modevalMon
The actual calculated modevals.
std::mutex m_modevalsMutex
Guards the modevals buffer during producer/consumer handoff.
mx::improc::eigenImage< float > m_respM
virtual void setupConfig()
int acquireAndCheckValid()
~dmRecon() noexcept
D'tor, declared and defined for noexcept.
std::string m_monShmimName
INDI_SETCALLBACK_DECL(dmRecon, m_indiP_fpsSource)
int processImage(void *curr_src, const dmModesShmimT &)
Process images for the dm modes shmimMonitor.
int setGPU()
Set the GPU index.
dev::frameGrabber< dmRecon > frameGrabberT
pcf::IndiProperty m_indiP_writeDMf
pcf::IndiProperty m_indiP_fpsSource
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
mx::improc::milkImage< float > m_modevalDiff
INDI_NEWCALLBACK_DECL(dmRecon, m_indiP_writeDMf)
std::atomic< bool > m_dmMaskReady
Flag indicating that the DM mask is ready for processing.
virtual int appStartup()
Startup function.
mx::improc::eigenImage< float > m_modevals
The calculated mode amplitudes.
static constexpr bool c_frameGrabber_flippable
mx::improc::eigenImage< float > m_mask
std::vector< size_t > m_maskIDX
The index of masked pixels.
mx::improc::eigenImage< float > m_command
The DM command, copied out of the incoming shmim.
dev::shmimMonitor< dmRecon, dmMaskShmimT > dmMaskSMT
dev::shmimMonitor< dmRecon, dmModesShmimT > dmModesSMT
virtual int appShutdown()
Shutdown the app.
mx::cuda::cublasHandle m_cublas
Handle for the cuBLAS library.
dev::telemeter< dmRecon > telemeterT
int m_numModes
Number of modes to reconstruct. If 0 (default) all modes in CM are used.
std::string m_respMPath
Optional response matrix. If set then CM modes are converted by this response.
int configureAcquisition()
sem_t m_smSemaphore
Semaphore used to synchronize the fg thread and the dm command thread.
dev::shmimMonitor< dmRecon, dmCommandShmimT > dmCommandSMT
int recordTelem(const telem_fgtimings *)
float m_fps
Current FPS from the FPS source.
int loadImageIntoStream(void *dest)
virtual void loadConfig()
int allocate(const dmModesShmimT &)
Allocate method for the dm modes shmimMonitor.
std::atomic< bool > m_writeDMf
mx::improc::milkImage< float > m_modeval
friend class dmRecon_test
pcf::IndiProperty m_indiP_fps
#define FRAMEGRABBER_SETUP_CONFIG(cfig)
Call frameGrabberT::setupConfig with error checking for frameGrabber.
#define FRAMEGRABBER_APP_LOGIC
Call frameGrabberT::appLogic with error checking for frameGrabber.
#define FRAMEGRABBER_APP_SHUTDOWN
Call frameGrabberT::appShutdown with error checking for frameGrabber.
#define FRAMEGRABBER_UPDATE_INDI
Call frameGrabberT::updateINDI with error checking for frameGrabber.
#define FRAMEGRABBER_LOAD_CONFIG(cfig)
Call frameGrabberT::loadConfig with error checking for frameGrabber.
#define FRAMEGRABBER_APP_STARTUP
Call frameGrabberT::appStartup with error checking for frameGrabber.
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define CREATE_REG_INDI_NEW_TOGGLESWITCH(prop, name)
Create and register a NEW INDI property as a standard toggle switch, using the standard callback name...
#define INDI_SETCALLBACK_DEFN(class, prop)
Define the callback for a set property request.
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
const pcf::IndiProperty & ipRecv
updateIfChanged(m_indiP_angle, "target", m_angle)
std::unique_lock< std::mutex > lock(m_indiMutex)
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static constexpr logPrioT LOG_INFO
Informational. The info log level is the lowest level recorded during normal operations.
#define SHMIMMONITORT_APP_STARTUP(SHMIMMONITORT)
Call shmimMonitorT::appStartup with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_UPDATE_INDI(SHMIMMONITORT)
Call shmimMonitorT::updateINDI with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_SETUP_CONFIG(SHMIMMONITORT, cfig)
Call shmimMonitorT::setupConfig with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_APP_LOGIC(SHMIMMONITORT)
Call shmimMonitorT::appLogic with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_APP_SHUTDOWN(SHMIMMONITORT)
Call shmimMonitorT::appShutodwn with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_LOAD_CONFIG(SHMIMMONITORT, cfig)
Call shmimMonitorT::loadConfig with error checking for a typedef-ed shmimMonitor.
A device base class which saves telemetry.
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
static std::string indiPrefix()
static std::string configSection()
static std::string configSection()
static std::string indiPrefix()
static std::string configSection()
static std::string indiPrefix()
@ OPERATING
The device is operating, other than homing.
Log entry recording framegrabber timings.
#define TELEMETER_APP_LOGIC
Call telemeter::appLogic with error checking.
#define TELEMETER_LOAD_CONFIG(cfig)
Call telemeter::loadConfig with error checking.
#define TELEMETER_APP_STARTUP
Call telemeter::appStartup with error checking.
#define TELEMETER_SETUP_CONFIG(cfig)
Call telemeter::setupConfig with error checking.
#define TELEMETER_APP_SHUTDOWN
Call telemeter::appShutdown with error checking.