API
 
Loading...
Searching...
No Matches
nnReconstructor_working.hpp
Go to the documentation of this file.
1/** \file nnReconstructor.hpp
2 * \brief The MagAO-X generic ImageStreamIO stream integrator
3 *
4 * \ingroup app_files
5 */
6
7#ifndef nnReconstructor_hpp
8#define nnReconstructor_hpp
9
10#include <NvInfer.h>
11#include <cuda_fp16.h>
12#include <cuda_runtime_api.h>
13#include <iostream>
14#include <fstream>
15#include <vector>
16#include <limits>
17
18#include <mx/improc/eigenCube.hpp>
19#include <mx/improc/eigenImage.hpp>
20
21#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
22#include "../../magaox_git_version.h"
23
24using namespace nvinfer1;
25
26// Logger for TensorRT info/warning/errors
27class Logger : public ILogger {
28 void log(Severity severity, const char* msg) noexcept override {
29 if (severity <= Severity::kWARNING) {
30 std::cout << msg << std::endl;
31 }
32 }
33};
34
35// #define MAGAOX_CURRENT_SHA1 0
36// #define MAGAOX_REPO_MODIFIED 0
37
38void halfToFloatArray(float* dst, const half* src, size_t num_elements) {
39 for (size_t i = 0; i < num_elements; ++i) {
40 dst[i] = __half2float(src[i]);
41 }
42}
43
44void floatToHalfArray(half* dst, const float* src, size_t num_elements) {
45 for (size_t i = 0; i < num_elements; ++i) {
46 dst[i] = __float2half(src[i]); // Convert each float to half-precision
47 }
48}
49
50
51namespace MagAOX
52{
53namespace app
54{
55
56class nnReconstructor : public MagAOXApp<true>, public dev::shmimMonitor<nnReconstructor>
57{
58 // Give the test harness access.
59 friend class nnReconstructor_test;
60
61 friend class dev::shmimMonitor<nnReconstructor>;
62
63 // The base shmimMonitor type
65
66 /// Floating point type in which to do all calculations.
67 typedef float realT;
68
69 public:
70 /** \name app::dev Configurations
71 *@{
72 */
73
74 ///@}
75
76 protected:
77 /** \name Configurable Parameters
78 *@{
79 */
80 std::string dataDirs; // Location where the data (onnx file, engine, WFS reference) is stored
81 std::string onnxFileName; // Name of the onnx files
82 std::string engineName; // Name of the engine
83 std::string engineDirs; // Name of the engine
84 bool rebuildEngine; // If true, it will rebuild the engine and save it at engineName
85
86 Logger logger; // The tensorRT logger
87 std::vector<char> engineData; // for loading the engine file.
88
89 IRuntime* runtime {nullptr};
90 ICudaEngine* engine {nullptr};
91 IExecutionContext* context {nullptr};
92 int inputC {0};
93 int inputH {0};
94 int inputW {0};
95 int inputSize {0};
96 int outputSize {0};
97
98 float* d_input {nullptr};
99 float* d_output {nullptr};
100 bool use_fp16 = false;
101
102 float imageNorm; // Normalization constant for the image intensities
103 float modalNorm; // Normalization constant for the modal coefficients
104
105 int m_pupPix; // Number of pixels in the pupil used for the Neural Network
106 int pup_offset1_x; // Horizontal offset to the first set of pupils
107 int pup_offset1_y; // Vertical offset to the first set of pupils
108 int pup_offset2_x; // Horizontal offset to the second set of pupils
109 int pup_offset2_y; // Horizontal offset to the second set of pupils
111 unsigned long frame_counter{ 0 };
112
113 int Npup{ 4 }; // Number of pupils
114 float *modeval{ nullptr };
115 float *pp_image{ nullptr };
116
117 size_t m_pwfsWidth{ 0 }; ///< The width of the image
118 size_t m_pwfsHeight{ 0 }; ///< The height of the image.
119
120 uint8_t m_pwfsDataType{ 0 }; ///< The ImageStreamIO type code.
121 size_t m_pwfsTypeSize{ 0 }; ///< The size of the type, in bytes.
122
123 // variables for sending the output to aol_modevals
124 std::string m_modevalChannel;
126 uint32_t m_modevalWidth {0}; ///< The width of the shmim
127 uint32_t m_modevalHeight {0}; ///< The height of the shmim
128 uint8_t m_modevalDataType {0}; ///< The ImageStreamIO type code.
129 size_t m_modevalTypeSize {0}; ///< The size of the type, in bytes.
130
131 bool m_modevalOpened {false};
132 bool m_modevalRestart {false};
133
134 public:
135 /// Default c'tor.
137
138 /// D'tor, declared and defined for noexcept.
142
143 virtual void setupConfig();
144
145 /// Implementation of loadConfig logic, separated for testing.
146 /** This is called by loadConfig().
147 */
149 mx::app::appConfigurator &_config /**< [in] an application configuration from which to load values*/ );
150
151 virtual void loadConfig();
152
153 /// Startup function
154 /**
155 *
156 */
157 virtual int appStartup();
158
159 /// Implementation of the FSM for nnReconstructor.
160 /**
161 * \returns 0 on no critical error
162 * \returns -1 on an error requiring shutdown
163 */
164 virtual int appLogic();
165
166 /// Shutdown the app.
167 /**
168 *
169 */
170 virtual int appShutdown();
171
172 // Custom functions
174
175 void load_engine(const std::string filename);
180
181 // void build_engine(){};
182
183 protected:
184 int allocate( const dev::shmimT &dummy /**< [in] tag to differentiate shmimMonitor parents.*/ );
185
186 int processImage( void *curr_src, ///< [in] pointer to start of current frame.
187 const dev::shmimT &dummy ///< [in] tag to differentiate shmimMonitor parents.
188 );
189};
190
191void nnReconstructor::load_engine(const std::string filename) {
192
193 std::ifstream file(filename, std::ios::binary);
194 if (!file) {
195 std::cout << "Error opening " << filename << std::endl;
196 }
197
198 file.seekg(0, std::ios::end);
199
200 engineData = std::vector<char>(file.tellg());
201 file.seekg(0, std::ios::beg);
202 file.read(engineData.data(), engineData.size());
203
204}
205
207
208 // Create the runtime and deserialize the engine
210 if (!runtime) {
211 std::cout << "Failed to createInferRuntime\n";
212 }
213
214 engine = runtime->deserializeCudaEngine(engineData.data(), engineData.size());
215 if (!engine) {
216 std::cout << "Failed to deserialize CUDA engine.\n";
217 } else {
218 std::cout << "Deserialized CUDA engine.\n";
219 }
220
221 context = engine->createExecutionContext();
222
223
224 int numIOTensors = engine->getNbIOTensors();
225 std::cout << "Number of IO Tensors: " << numIOTensors << std::endl;
226
227 auto inputName = engine->getIOTensorName(0);
228 auto outputName = engine->getIOTensorName(1);
229 std::cout << "Tensor IO names: " << inputName << " " << outputName << std::endl;
230
231 const auto inputDims = engine->getTensorShape(inputName);
232 const auto outputDims = engine->getTensorShape(outputName);
233 inputC = inputDims.d[1];
234 inputH = inputDims.d[2];
235 inputW = inputDims.d[3];
237
238 outputSize = outputDims.d[1];
239 std::cout << "Tensor input dimensions: " << inputC << "x" << inputH << "x" << inputW << std::endl;
240 std::cout << "Tensor output dimensions: " << outputSize << std::endl;
241
242}
243
245
246 // Allocate device memory for input and output
247 if (use_fp16) {
248 // Allocate FP16 memory
249 cudaMalloc((void**)&d_input, inputSize * sizeof(half));
250 cudaMalloc((void**)&d_output, outputSize * sizeof(half));
251 } else {
252 // Allocate FP32 memory
253 cudaMalloc((void**)&d_input, inputSize * sizeof(float));
254 cudaMalloc((void**)&d_output, outputSize * sizeof(float));
255 }
256
257 //cudaMalloc((void**)&d_input, inputSize * sizeof(float));
258 //cudaMalloc((void**)&d_output, outputSize * sizeof(float));
259
260}
261
263 if(d_input)
265
266 if(d_output)
268}
269
271 if(context)
272 delete context;
273 if(engine)
274 delete engine;
275 if(runtime)
276 delete runtime;
277};
278
280{
281 // Check if processImage is running
282 // while(m_dmStream.md[0].write == 1);
283
284 m_modevalStream.md[0].write = 1;
286 m_modevalStream.md[0].cnt0++;
287 m_modevalStream.md[0].write = 0;
288
290
291 return 0;
292}
293
294inline nnReconstructor::nnReconstructor() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
295{
296 return;
297}
298
300{
301 std::cout << "setupConfig()" << std::endl;
303
304 config.add( "parameters.dataDirs",
305 "",
306 "parameters.dataDirs",
307 argType::Required,
308 "parameters",
309 "dataDirs",
310 false,
311 "string",
312 "The path to the directory with the onnx model." );
313
314 config.add( "parameters.engineDirs",
315 "",
316 "parameters.engineDirs",
317 argType::Required,
318 "parameters",
319 "engineDirs",
320 false,
321 "string",
322 "The path to the directory with the TRT engine." );
323
324 config.add( "parameters.onnxFileName",
325 "",
326 "parameters.onnxFileName",
327 argType::Required,
328 "parameters",
329 "onnxFileName",
330 false,
331 "string",
332 "Name of the Neural Net ONNX file" );
333
334 config.add( "parameters.engineName",
335 "",
336 "parameters.engineName",
337 argType::Required,
338 "parameters",
339 "engineName",
340 false,
341 "string",
342 "Name of the TRT engine." );
343 config.add( "parameters.rebuildEngine",
344 "",
345 "parameters.rebuildEngine",
346 argType::Required,
347 "parameters",
348 "rebuildEngine",
349 false,
350 "bool",
351 "If true the engine will be rebuild." );
352
353 config.add( "parameters.imageNorm",
354 "",
355 "parameters.imageNorm",
356 argType::Required,
357 "parameters",
358 "imageNorm",
359 false,
360 "float",
361 "Normalization term for the preprocessed images." );
362
363 config.add( "parameters.modalNorm",
364 "",
365 "parameters.modalNorm",
366 argType::Required,
367 "parameters",
368 "modalNorm",
369 false,
370 "float",
371 "Normalization term for the modal coefficients." );
372
373 config.add( "parameters.channel",
374 "",
375 "parameters.channel",
376 argType::Required,
377 "parameters",
378 "channel",
379 false,
380 "string",
381 "The output channel." );
382
383 config.add( "parameters.m_pupPix",
384 "",
385 "parameters.m_pupPix",
386 argType::Required,
387 "parameters",
388 "m_pupPix",
389 false,
390 "int",
391 "Number of pixels across a PWFS pupil." );
392
393 config.add( "parameters.pup_offset1_x",
394 "",
395 "parameters.pup_offset1_x",
396 argType::Required,
397 "parameters",
398 "pup_offset1_x",
399 false,
400 "int",
401 "Horizontal offset to the top left of the closest set op PWFS pupils." );
402
403 config.add( "parameters.pup_offset1_y",
404 "",
405 "parameters.pup_offset1_y",
406 argType::Required,
407 "parameters",
408 "pup_offset1_y",
409 false,
410 "int",
411 "Vertical offset to the top left of the closest set op PWFS pupils." );
412
413 config.add( "parameters.pup_offset2_x",
414 "",
415 "parameters.pup_offset2_x",
416 argType::Required,
417 "parameters",
418 "pup_offset2_x",
419 false,
420 "int",
421 "Horizontal offset to the top left of the furthest set op PWFS pupils." );
422
423 config.add( "parameters.pup_offset2_y",
424 "",
425 "parameters.pup_offset2_y",
426 argType::Required,
427 "parameters",
428 "pup_offset2_y",
429 false,
430 "int",
431 "Vertical offset to the top left of the furthest set op PWFS pupils." );
432
433}
434
435inline int nnReconstructor::loadConfigImpl( mx::app::appConfigurator &_config )
436{
437 std::cout << "loadConfigImpl()" << std::endl;
439
440 _config( dataDirs, "parameters.dataDirs" );
441 _config( engineDirs, "parameters.engineDirs" );
442 _config( onnxFileName, "parameters.onnxFileName" );
443 _config( engineName, "parameters.engineName" );
444 _config( rebuildEngine, "parameters.rebuildEngine" );
445
446 _config( imageNorm, "parameters.imageNorm" );
447 _config( modalNorm, "parameters.modalNorm" );
448 _config( m_modevalChannel, "parameters.channel");
449
450 _config( m_pupPix, "parameters.m_pupPix" );
451 _config( pup_offset1_x, "parameters.pup_offset1_x" );
452 _config( pup_offset1_y, "parameters.pup_offset1_y" );
453 _config( pup_offset2_x, "parameters.pup_offset2_x" );
454 _config( pup_offset2_y, "parameters.pup_offset2_y" );
455
456 if( true )
457 {
458 std::cout << "Debug configuration loading: " << std::endl;
459 std::cout << "dataDirs: " << dataDirs << std::endl;
460 std::cout << "engineDirs: " << engineDirs << std::endl;
461 std::cout << "onnxFileName: " << onnxFileName << std::endl;
462 std::cout << "engineName: " << engineName << std::endl;
463 std::cout << "rebuildEngine: " << rebuildEngine << std::endl;
464 std::cout << "imageNorm: " << imageNorm << std::endl;
465 std::cout << "modalNorm: " << modalNorm << std::endl;
466 std::cout << "modeval Channel: " << m_modevalChannel << std::endl;
467
468 std::cout << "m_pupPix: " << m_pupPix << std::endl;
469 std::cout << "pup_offset1_x: " << pup_offset1_x << std::endl;
470 std::cout << "pup_offset1_y: " << pup_offset1_y << std::endl;
471 std::cout << "pup_offset2_x: " << pup_offset2_x << std::endl;
472 std::cout << "pup_offset2_y: " << pup_offset2_y << std::endl;
473 }
474
475 return 0;
476}
477
478inline void nnReconstructor::loadConfig()
479{
480 loadConfigImpl( config );
481}
482
484{
485 if( shmimMonitorT::appStartup() < 0 )
486 {
487 return log<software_error, -1>( { __FILE__, __LINE__ } );
488 }
489
490 std::string full_filepath = engineDirs + "/" + engineName;
491 std::cout << "file: " << full_filepath << std::endl;
492
496
497 // state(stateCodes::READY);
499 return 0;
500}
501
502inline int nnReconstructor::appLogic()
503{
504 if( shmimMonitorT::appLogic() < 0 )
505 {
506 return log<software_error, -1>( { __FILE__, __LINE__ } );
507 }
508
509 std::unique_lock<std::mutex> lock( m_indiMutex );
510
511 if( shmimMonitorT::updateINDI() < 0 )
512 {
514 }
515
516 return 0;
517}
518
520{
522
523 if( pp_image )
524 {
525 delete[] pp_image;
526 }
527 if( modeval )
528 {
529 delete[] modeval;
530 }
531
534
535 return 0;
536}
537
538inline int nnReconstructor::allocate( const dev::shmimT &dummy )
539{
540 std::cout << "allocate()" << std::endl;
541 static_cast<void>( dummy ); // be unused
542
543 // Wavefront sensor setup
546 std::cout << "Width: " << m_pwfsWidth << " Height: " << m_pwfsHeight << std::endl;
547
549 std::cout << "Pixels: " << pixels_per_quadrant << std::endl;
550 pp_image = new float[Npup * pixels_per_quadrant];
551 modeval = new float[outputSize];
552 memset( pp_image, 0, sizeof( float ) * Npup * pixels_per_quadrant );
553 memset( modeval, 0, sizeof( float) * outputSize);
554
555 std::cout << "Close shmims" << std::endl;
556 // Allocate the DM shmim interface
557 if(m_modevalOpened){
559 }
560
561 std::cout << "Open shmims" << std::endl;
562 m_modevalOpened = false;
563 m_modevalRestart = false; //Set this up front, since we're about to restart.
564
566 if(m_modevalStream.md[0].sem < 10){
568 }else{
569 m_modevalOpened = true;
570 }
571 }
572
573 std::cout << "Done!" << std::endl;
574 if(!m_modevalOpened){
575 log<text_log>( m_modevalChannel + " not opened.", logPrio::LOG_NOTICE);
576 return -1;
577 }else{
578 m_modevalWidth = m_modevalStream.md->size[0];
579 m_modevalHeight = m_modevalStream.md->size[1];
580
581 m_modevalDataType = m_modevalStream.md->datatype;
582 m_modevalTypeSize = sizeof(float);
583
584 log<text_log>( "Opened " + m_modevalChannel + " " + std::to_string(m_modevalWidth) + " x " + std::to_string(m_modevalHeight) + " with data type: " + std::to_string(m_modevalDataType), logPrio::LOG_NOTICE);
585 }
586
587
588 return 0;
589}
590
591inline int nnReconstructor::processImage( void *curr_src, const dev::shmimT &dummy )
592{
593 static_cast<void>( dummy ); // be unused
594
595 // aol_imwfs2 is reference and dark subtracted and is power normalized.
596 Eigen::Map<eigenImage<unsigned short>> pwfsIm(static_cast<unsigned short *>( curr_src ), m_pwfsHeight, m_pwfsWidth );
597
598 // Split up the four pupils for the Neural Network.
599 int ki = 0;
600
601 for( int col_i = 0; col_i < m_pupPix; ++col_i )
602 {
603 for( int row_i = 0; row_i < m_pupPix; ++row_i )
604 {
609
610 ++ki;
611 }
612 }
613 // Copy input data to device
615
616 // Run inference
617 void* buffers[] = {d_input, d_output};
618 context->executeV2(buffers);
619
620 // Copy output data back to host
622
623 if(frame_counter % 2000 == 0)
624 std::cout << "HOWDY" << std::endl;
625
626 // Send modal coefficients to the correct stream
628
630
631 return 0;
632}
633
634} // namespace app
635} // namespace MagAOX
636
637#endif // nnReconstructor_hpp
void log(Severity severity, const char *msg) noexcept override
stateCodes::stateCodeT state()
Get the current state code.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
std::mutex m_indiMutex
Mutex for locking INDI communications.
uint32_t m_width
The width of the images in the stream.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
int updateINDI()
Update the INDI properties for this device controller.
int appLogic()
Checks the shmimMonitor thread.
uint32_t m_height
The height of the images in the stream.
int appShutdown()
Shuts down the shmimMonitor thread.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
float realT
Floating point type in which to do all calculations.
size_t m_pwfsWidth
The width of the image.
virtual int appStartup()
Startup function.
virtual int appLogic()
Implementation of the FSM for nnReconstructor.
virtual int appShutdown()
Shutdown the app.
size_t m_pwfsHeight
The height of the image.
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
int allocate(const dev::shmimT &dummy)
uint32_t m_modevalHeight
The height of the shmim.
uint8_t m_pwfsDataType
The ImageStreamIO type code.
virtual int appStartup()
Startup function.
size_t m_modevalTypeSize
The size of the type, in bytes.
virtual int appLogic()
Implementation of the FSM for nnReconstructor.
void load_engine(const std::string filename)
int processImage(void *curr_src, const dev::shmimT &dummy)
size_t m_pwfsTypeSize
The size of the type, in bytes.
uint8_t m_modevalDataType
The ImageStreamIO type code.
virtual int appShutdown()
Shutdown the app.
~nnReconstructor() noexcept
D'tor, declared and defined for noexcept.
uint32_t m_modevalWidth
The width of the shmim.
dev::shmimMonitor< nnReconstructor > shmimMonitorT
@ OPERATING
The device is operating, other than homing.
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:26
void halfToFloatArray(float *dst, const half *src, size_t num_elements)
void floatToHalfArray(half *dst, const float *src, size_t num_elements)