12#include <mx/improc/eigenCube.hpp>
13#include <mx/improc/eigenImage.hpp>
14#include <mx/sigproc/gramSchmidt.hpp>
15#include <mx/math/templateBLAS.hpp>
17#include "../../libMagAOX/libMagAOX.hpp"
18#include "../../magaox_git_version.h"
20#include <mx/math/cuda/cudaPtr.hpp>
21#include <mx/math/cuda/cublasHandle.hpp>
22#include <mx/math/cuda/templateCublas.hpp>
23#include <mx/math/eigenLapack.hpp>
24#include <mx/sigproc/basisUtils2D.hpp>
348 config.add(
"recon.loopNumber",
356 "The loop number. Default is 1 as in aol1." );
358 config.add(
"recon.respMPath",
366 "Optional response matrix. If set then CM modes are converted by this response." );
368 config.add(
"recon.numModes",
376 "Number of modes to reconstruct. If 0 (default) all modes in CM are used." );
378 config.add(
"recon.inverseNumModes",
380 "recon.inverseNumModes",
386 "Number of modes to use for pseudo-inverse truncation. If 0 (default) all modes are used." );
388 config.add(
"recon.fpsSource",
396 "Device name for getting fps of the loop. This device should have *.fps.current. "
397 "Default is camwfs" );
399 config.add(
"recon.gpuIndex",
407 "Index of the GPU to use for calculations. Default is 0." );
409 config.add(
"recon.useGPU",
417 "Flag controlling whether the GPU is used for calculations. Default is false." );
491 mx::fits::fitsFile<float>
ff;
575 "[{}] {}\nNOT USING GPU",
584 std::string
msg = std::format(
"CUDA: found {} devices\n",
deviceCount );
589 msg +=
" greater than devicecntMax\n";
593 msg +=
" less than zero\n";
598 msg +=
" no devices found!\nNOT USING GPU";
612 msg += std::format(
"cudaGetDeviceProperties returned error: "
613 "[{}] {}\nNOT USING GPU",
627 msg += std::format(
"cudaGetDeviceAttribute returned error: "
628 "[{}] {}\nNOT USING GPU",
637 msg += std::format(
" Device {} / {} [ {} ] has compute capability {}.{}.\n",
644 msg += std::format(
" Total amount of global memory: {} MBytes\n",
645 (
float)
deviceProp.totalGlobalMem / 1048576.0f );
647 msg += std::format(
" Multiprocessors: {}\n",
deviceProp.multiProcessorCount );
664 msg += std::format(
"cudaSetDevice returned error: "
665 "[{}] {}\nNOT USING GPU",
680 msg += std::format(
"cublasHandle create returned error: "
681 "[{}] {}\nNOT USING GPU",
690 msg +=
" cuBLAS initialized";
720 std::cerr <<
"modes not ready\n";
746 mx::sys::milliSleep( 1000 );
778 mx::sys::milliSleep( 1000 );
783 mx::improc::eigenCube<realT>
tmpc;
791 for(
int p = 0; p <
tmpc.planes(); ++p )
807 mx::fits::fitsFile<float>
ff;
839 std::cerr <<
"PInv: " <<
m_PInv.rows() <<
' ' <<
m_PInv.cols() <<
'\n';
841 mx::fits::fitsFile<float>
ff;
844 log<text_log>( std::format(
"Inverted CMmodesDM. Rejected {} "
845 "of {} modes, condition numer = {}",
852 std::cerr <<
"modes ready\n";
860 std::cerr <<
"mask not ready\n";
884 mx::sys::milliSleep( 1000 );
909 std::cerr <<
n <<
' ' <<
nmax <<
'\n';
911 std::cerr <<
"Got mask of size " <<
m_mask.rows() <<
" x " <<
m_mask.cols() <<
" with " <<
m_maskIDX.size()
912 <<
" good pixels.\n";
915 std::cerr <<
"mask ready\n";
923 std::cerr <<
"command not ready\n";
931 mx::sys::milliSleep( 1000 );
939 mx::sys::milliSleep( 1000 );
972 if(
ec != mx::error_t::noerror )
975 "error uploading PInv to GPU: [{}] {}", mx::errorName(
ec ), mx::errorMessage(
ec ) ) } );
979 if(
ec != mx::error_t::noerror )
982 "error allocating command on GPU: [{}] {}", mx::errorName(
ec ), mx::errorMessage(
ec ) ) } );
986 if(
ec != mx::error_t::noerror )
989 "error allocating modevals on GPU: [{}] {}", mx::errorName(
ec ), mx::errorMessage(
ec ) ) } );
1000 std::cerr <<
"command ready\n";
1033 if(
ec != mx::error_t::noerror )
1036 "error uploading command to GPU: [{}] {}", mx::errorName(
ec ), mx::errorMessage(
ec ) ) } );
1057 return log<
software_error, -1>( { std::format(
"error downloading modevals from GPU: [{}] {}",
1063 if(
ec != mx::error_t::noerror )
1066 "error downloading modevals from GPU: [{}] {}", mx::errorName(
ec ), mx::errorMessage(
ec ) ) } );
1111 mx::sys::milliSleep( 100 );
1177 ". Source process will need to be restarted." } );
1212 std::cerr <<
"startAcquisition\n";
1269 if(
ipRecv.find(
"current" ) !=
true )
1274 std::lock_guard<std::mutex> guard( m_indiMutex );
1276 realT fps =
ipRecv[
"current"].get<
float>();
1291 if(
ipRecv.find(
"toggle" ) !=
true )
1296 std::lock_guard<std::mutex> guard( m_indiMutex );
1298 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On )
1302 updateSwitchIfChanged( m_indiP_writeDMf,
"toggle", pcf::IndiElement::On );
1308 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.
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.
float realT
Floating point type in which to do all calculations.
mx::improc::milkImage< float > m_modevalMon
The actual calculated modevals.
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.
bool m_dmModesReady
Flag indicating that the DM modes are ready for processing.
int setGPU()
Set the GPU index.
dev::frameGrabber< dmRecon > frameGrabberT
pcf::IndiProperty m_indiP_writeDMf
pcf::IndiProperty m_indiP_fpsSource
bool m_fgWaiting
Flag indicating that the FG thread is waiting for the command thread.
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)
virtual int appStartup()
Startup function.
bool m_updated
Flag indicating that the mode vals have been updated.
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.
bool m_commandReady
Flag indicating that all sizes match and arrays are ready for processing.
dev::shmimMonitor< dmRecon, dmCommandShmimT > dmCommandSMT
bool m_dmMaskReady
Flag indicating that the DM mask is ready for processing.
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.
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.
@ OPERATING
The device is operating, other than homing.
#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()
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.