From 59339e44bd69fb83e40321f343ef76d9ba091966 Mon Sep 17 00:00:00 2001 From: albertoesmp Date: Mon, 18 Sep 2023 19:56:31 +0200 Subject: [PATCH] Improved HDA wrt PulseRecorder. Added script to plot pulse records. --- scripts/debug/fullwave_plotter.py | 0 scripts/debug/hda_diff_report.py | 0 scripts/debug/hda_pulse_records_plotter.py | 385 ++++++++++++++++++ scripts/debug/hda_simstep_plotter.py | 2 +- scripts/debug/hda_xyzcloud_report.py | 0 scripts/debug/plot_budding_metrics.py | 0 scripts/debug/plot_log_data.py | 0 src/dataanalytics/HDA_OfstreamWrapper.h | 63 +++ src/dataanalytics/HDA_PulseRecorder.cpp | 31 +- src/dataanalytics/HDA_PulseRecorder.h | 38 +- src/dataanalytics/HDA_RecordBuffer.h | 50 +-- src/main/helios_version.cpp | 2 +- src/scanner/MultiScanner.cpp | 6 + src/scanner/MultiScanner.h | 3 + src/scanner/Scanner.h | 3 + src/scanner/ScanningDevice.cpp | 12 +- src/scanner/ScanningDevice.h | 7 + src/scanner/SingleScanner.cpp | 6 + src/scanner/SingleScanner.h | 3 + .../detector/FullWaveformPulseRunnable.cpp | 6 +- 20 files changed, 561 insertions(+), 56 deletions(-) mode change 100644 => 100755 scripts/debug/fullwave_plotter.py mode change 100644 => 100755 scripts/debug/hda_diff_report.py create mode 100755 scripts/debug/hda_pulse_records_plotter.py mode change 100644 => 100755 scripts/debug/hda_simstep_plotter.py mode change 100644 => 100755 scripts/debug/hda_xyzcloud_report.py mode change 100644 => 100755 scripts/debug/plot_budding_metrics.py mode change 100644 => 100755 scripts/debug/plot_log_data.py create mode 100644 src/dataanalytics/HDA_OfstreamWrapper.h diff --git a/scripts/debug/fullwave_plotter.py b/scripts/debug/fullwave_plotter.py old mode 100644 new mode 100755 diff --git a/scripts/debug/hda_diff_report.py b/scripts/debug/hda_diff_report.py old mode 100644 new mode 100755 diff --git a/scripts/debug/hda_pulse_records_plotter.py b/scripts/debug/hda_pulse_records_plotter.py new file mode 100755 index 000000000..ba7a972db --- /dev/null +++ b/scripts/debug/hda_pulse_records_plotter.py @@ -0,0 +1,385 @@ +import sys +import os +import time +import numpy as np +import matplotlib.pyplot as plt + + +# --- FUNCTIONS --- # +# ------------------- # +def print_help(): + print( +''' +Input arguments: + 1 -> Path to the first directory containing simulation records + 2 -> Path to the second directory containing simulation records + 3 -> Path to the directory where plots will be stored +''' + ) + + +def parse_args(helpf=print_help): + """Parse input arguments. Raise an exception if not correct arguments were + given""" + if len(sys.argv) == 1: + helpf() + exit(0) + elif len(sys.argv) < 4: + raise Exception( + '{m} arguments were given but 3 are required' + .format(m=len(sys.argv)-1) + ) + dira_path = sys.argv[1] + if not validate_directory(dira_path): + raise Exception( + 'The directory "{d}"\n' + 'was given as the first directory of records, but it is not valid' + ) + dirb_path = sys.argv[2] + if not validate_directory(dirb_path): + raise Exception( + 'The directory "{d}"\n' + 'was given as the second directory of records, but it is not valid' + ) + dirout_path = sys.argv[3] + if not validate_directory(dirout_path): + raise Exception( + 'The directory "{d}"\n' + 'was given as the third directory for plots, but it is not valid' + ) + return { + 'dira_path': dira_path, + 'dirb_path': dirb_path, + 'dirout_path': dirout_path + } + + +def validate_directory(path): + """Check path points to a valid existent directory. + If it does not exist and it cannot be created, then it is not valid""" + if os.path.exists(path): + if os.path.isdir(path): + return True + else: + return False + else: + os.mkdir(path, mode=0o775) + if os.path.exists(path): + return True + return False + + +def read_records(path, sep=','): + """Read all record files contained in the directory pointed by given + path""" + # Read vectorial records + intensity_calc = read_record(os.path.join( + path, 'intensity_calc.csv' + ), sep) + # Return key-word records + return { + # Intensity calculation records + 'incidence_angle_rad': intensity_calc[:, 0], + 'target_range_m': intensity_calc[:, 1], + 'target_area_m2': intensity_calc[:, 2], + 'radius_m': intensity_calc[:, 3], + 'bdrf': intensity_calc[:, 4], + 'cross_section': intensity_calc[:, 5], + 'received_power': intensity_calc[:, 6] + } + + +def read_record(path, sep): + """Read given record file + :param path: The path to the record file to be read + :param sep: The separator used in the record file + :return: None if the record file could not be read, the data as a numpy + array otherwise + """ + if os.path.exists(path) and os.path.isfile(path): + return np.loadtxt(path, delimiter=sep) + return None + + +def plot_records(arec, brec, outdir): + """Do plots for each case and export them in given output directory + :param arec: The records of the first case + :param brec: The records of the second case + :param outdir: The output directory where generated plots must be + written + """ + do_incidence_angle_plots(arec, brec, outdir) + do_by_incidence_angle_plots(arec, brec, outdir) + + +def validate_record(key, rec, recid): + """Check that the record with given key is available + :return: True if the record is valid (available data), False otherwise + """ + if key not in rec or rec.get(key, None) is None: + print( + 'Record "{key}" is not available for {recid} records' + .format( + key=key, + recid=recid + ) + ) + return False + return True + + +def init_figure(figsize=(20, 12)): + """Initialize a matplotlib's figure context""" + fig = plt.figure( + figsize=figsize + ) + return fig + + +def do_incidence_angle_subplot( + fig, ax, phi, label=None, title=None, xlabel=None, ylabel=None, bins=32, + log=False +): + if title is not None: + ax.set_title(title, fontsize=20) + hist = ax.hist(phi, bins=bins, label=label, log=log) + ax.axvline(x=np.mean(phi), color='tab:orange', lw=3, label='$\\mu$') + if xlabel is not None: + ax.set_xlabel(xlabel, fontsize=16) + if ylabel is not None: + ax.set_ylabel(ylabel, fontsize=16) + ax.tick_params(axis='both', which='both', labelsize=14) + ax.legend(loc='upper right', fontsize=14) + ax.grid('both') + ax.set_axisbelow(True) + + +def do_incidence_angle_plots(arec, brec, outdir): + # Validate incidence angle data + if not validate_record('incidence_angle_rad', arec, 'a') or \ + not validate_record('incidence_angle_rad', brec, 'b'): + print('Cannot do incidence angle plots') + return + + # Do the incidence angle plots + fig = init_figure() # Initialize figure + ax = fig.add_subplot(2, 2, 1) # Initialize phi(a) subplot + do_incidence_angle_subplot( + fig, ax, arec['incidence_angle_rad'], + label='$\\varphi(a)$', + title='A-Incidence angle ($\\varphi$) in rad', + xlabel='$\\varphi(a)$', + ylabel='cases' + ) + ax = fig.add_subplot(2, 2, 3) # Initialize phi(a) log subplot + do_incidence_angle_subplot( + fig, ax, arec['incidence_angle_rad'], + label='$\\varphi(a)$', + title='A-Incidence angle ($\\varphi$) in rad (logarithmic)', + xlabel='$\\varphi(a)$', + ylabel='cases', + log=True + ) + ax = fig.add_subplot(2, 2, 2) # Initialize phi(b) subplot + do_incidence_angle_subplot( + fig, ax, brec['incidence_angle_rad'], + label='$\\varphi(b)$', + title='B-Incidence angle ($\\varphi$) in rad', + xlabel='$\\varphi(b)$', + ylabel='cases' + ) + ax = fig.add_subplot(2, 2, 4) # Initialize phi(a) log subplot + do_incidence_angle_subplot( + fig, ax, brec['incidence_angle_rad'], + label='$\\varphi(b)$', + title='B-Incidence angle ($\\varphi$) in rad (logarithmic)', + xlabel='$\\varphi(b)$', + ylabel='cases', + log=True + ) + fig.tight_layout() + # Save figure to file and remove it from memory + fig.savefig( + os.path.join(outdir, 'incidence_angle_distribution.png') + ) + fig.clear() + plt.close(fig) + + +def do_y_by_x_subplot( + fig, ax, x, y, title=None, xlabel=None, ylabel=None, + color='black' +): + if title is not None: + ax.set_title(title, fontsize=14) + ax.scatter(x, y, c=color, s=8) + if xlabel is not None: + ax.set_xlabel(xlabel, fontsize=12) + if ylabel is not None: + ax.set_ylabel(ylabel, fontsize=12) + ax.tick_params(axis='both', which='both', labelsize=12) + ax.grid('both') + ax.set_axisbelow(True) + + +def do_by_incidence_angle_plots(arec, brec, outdir): + # Validate classification calculation data + if not validate_record('incidence_angle_rad', arec, 'a') or \ + not validate_record('target_range_m', arec, 'a') or \ + not validate_record('target_area_m2', arec, 'a') or \ + not validate_record('radius_m', arec, 'a') or \ + not validate_record('bdrf', arec, 'a') or \ + not validate_record('cross_section', arec, 'a') or \ + not validate_record('received_power', arec, 'a') or \ + not validate_record('incidence_angle_rad', brec, 'b') or \ + not validate_record('target_range_m', brec, 'b') or \ + not validate_record('target_area_m2', brec, 'b') or \ + not validate_record('radius_m', brec, 'b') or \ + not validate_record('bdrf', brec, 'b') or \ + not validate_record('cross_section', brec, 'b') or \ + not validate_record('received_power', brec, 'b'): + print('Cannot do by incidence angle plots') + return + # Do the "by incidence angle" plots + fig = init_figure() # Initialize figure + ax = fig.add_subplot(3, 4, 1) # Initialize target range A subplot + do_y_by_x_subplot( + fig, ax, arec['incidence_angle_rad'], arec['target_range_m'], + title='A-Target range (m)', + xlabel='Incidence angle (rad)', + ylabel='Target range (m)', + color='black' + ) + ax = fig.add_subplot(3, 4, 2) # Initialize target area A subplot + do_y_by_x_subplot( + fig, ax, arec['incidence_angle_rad'], arec['target_area_m2'], + title='A-Target area ($m^2$)', + xlabel='Incidence angle (rad)', + ylabel='Target area ($m^2$)', + color='tab:blue' + ) + ax = fig.add_subplot(3, 4, 5) # Initialize radius A subplot + do_y_by_x_subplot( + fig, ax, arec['incidence_angle_rad'], arec['radius_m'], + title='A-Radius (m)', + xlabel='Incidence angle (rad)', + ylabel='Radius (m)', + color='tab:red' + ) + ax = fig.add_subplot(3, 4, 6) # Initialize BDRF A subplot + do_y_by_x_subplot( + fig, ax, arec['incidence_angle_rad'], arec['bdrf'], + title='A-BDRF', + xlabel='Incidence angle (rad)', + ylabel='BDRF', + color='tab:green' + ) + ax = fig.add_subplot(3, 4, 9) # Initialize Cross-section A subplot + do_y_by_x_subplot( + fig, ax, arec['incidence_angle_rad'], arec['cross_section'], + title='A-Cross-section ($m^2$)', + xlabel='Incidence angle (rad)', + ylabel='Cross-section ($m^2$)', + color='tab:orange' + ) + ax = fig.add_subplot(3, 4, 10) # Initialize received power A subplot + do_y_by_x_subplot( + fig, ax, arec['incidence_angle_rad'], arec['received_power'], + title='A-Received power', + xlabel='Incidence angle (rad)', + ylabel='Received power', + color='tab:purple' + ) + ax = fig.add_subplot(3, 4, 3) # Initialize target range B subplot + do_y_by_x_subplot( + fig, ax, brec['incidence_angle_rad'], brec['target_range_m'], + title='B-Target range (m)', + xlabel='Incidence angle (rad)', + ylabel='Target range (m)', + color='black' + ) + ax = fig.add_subplot(3, 4, 4) # Initialize target area B subplot + do_y_by_x_subplot( + fig, ax, brec['incidence_angle_rad'], brec['target_area_m2'], + title='B-Target area ($m^2$)', + xlabel='Incidence angle (rad)', + ylabel='Target area ($m^2$)', + color='tab:blue' + ) + ax = fig.add_subplot(3, 4, 7) # Initialize radius B subplot + do_y_by_x_subplot( + fig, ax, brec['incidence_angle_rad'], brec['radius_m'], + title='B-Radius (m)', + xlabel='Incidence angle (rad)', + ylabel='Radius (m)', + color='tab:red' + ) + ax = fig.add_subplot(3, 4, 8) # Initialize BDRF B subplot + do_y_by_x_subplot( + fig, ax, brec['incidence_angle_rad'], brec['bdrf'], + title='B-BDRF', + xlabel='Incidence angle (rad)', + ylabel='BDRF', + color='tab:green' + ) + ax = fig.add_subplot(3, 4, 11) # Initialize Cross-section B subplot + do_y_by_x_subplot( + fig, ax, brec['incidence_angle_rad'], brec['cross_section'], + title='B-Cross-section ($m^2$)', + xlabel='Incidence angle (rad)', + ylabel='Cross-section ($m^2$)', + color='tab:orange' + ) + ax = fig.add_subplot(3, 4, 12) # Initialize received power B subplot + do_y_by_x_subplot( + fig, ax, brec['incidence_angle_rad'], brec['received_power'], + title='B-Received power', + xlabel='Incidence angle (rad)', + ylabel='Received power', + color='tab:purple' + ) + fig.tight_layout() + # Save figure to file and remove it from memory + fig.savefig( + os.path.join(outdir, 'plots_by_incidence_angle.png') + ) + fig.clear() + plt.close(fig) + + + +# --- M A I N --- # +# ------------------- # +if __name__ == '__main__': + # Prepare plotter + args = parse_args() + sep = ',' + # Read A records + print( + 'Reading A-records from "{path}" ...' + .format(path=args['dira_path']) + ) + start = time.perf_counter() + arec = read_records(args['dira_path'], sep=sep) + end = time.perf_counter() + print('Read A-records in {t} seconds'.format(t=end-start)) + # Read B records + print( + 'Reading B-records from "{path}" ...' + .format(path=args['dirb_path']) + ) + start = time.perf_counter() + brec = read_records(args['dirb_path'], sep=sep) + end = time.perf_counter() + print('Read B-records in {t} seconds'.format(t=end-start)) + # Plot records + print( + 'Generating plots at "{path}" ...' + .format( + path=args['dirout_path'] + ) + ) + start = time.perf_counter() + plot_records(arec, brec, args['dirout_path']) + end = time.perf_counter() + print('Generated plots in {t} seconds'.format(t=end-start)) diff --git a/scripts/debug/hda_simstep_plotter.py b/scripts/debug/hda_simstep_plotter.py old mode 100644 new mode 100755 index 92d8e0e43..9ce472fd7 --- a/scripts/debug/hda_simstep_plotter.py +++ b/scripts/debug/hda_simstep_plotter.py @@ -45,7 +45,7 @@ def parse_args(helpf=print_help): if not validate_directory(dirout_path): raise Exception( 'The directory "{d}"\n' - 'was given as the third directory of records, but it is not valid' + 'was given as the third directory for plots, but it is not valid' ) return { 'dira_path': dira_path, diff --git a/scripts/debug/hda_xyzcloud_report.py b/scripts/debug/hda_xyzcloud_report.py old mode 100644 new mode 100755 diff --git a/scripts/debug/plot_budding_metrics.py b/scripts/debug/plot_budding_metrics.py old mode 100644 new mode 100755 diff --git a/scripts/debug/plot_log_data.py b/scripts/debug/plot_log_data.py old mode 100644 new mode 100755 diff --git a/src/dataanalytics/HDA_OfstreamWrapper.h b/src/dataanalytics/HDA_OfstreamWrapper.h new file mode 100644 index 000000000..bcec285d9 --- /dev/null +++ b/src/dataanalytics/HDA_OfstreamWrapper.h @@ -0,0 +1,63 @@ +#ifdef DATA_ANALYTICS + +#include +#include +#include + +// TODO Rethink : Document + +namespace helios { namespace analytics{ + +class HDA_OfstreamWrapper{ +protected: + // *** ATTRIBUTES *** // + // ******************** // + std::ofstream ofs; + /** + * @brief The separator between recorded elements + */ + std::string sep; + bool hasWrittenSomething; + +public: + // *** CONSTRUCTION / DESTRUCTION *** // + // ************************************ // + HDA_OfstreamWrapper(std::string const &outpath, std::string const &sep=",") : + ofs(outpath, std::ios_base::out), + sep(sep), + hasWrittenSomething(false) + {} + virtual ~HDA_OfstreamWrapper() = default; + + // *** OUTPUT FILE STREAM METHODS *** // + // ************************************ // + inline bool is_open() {return ofs.is_open();} + inline void close() {return ofs.close();} + + // *** OUTPUT FILE STREAM OPERATORS *** // + // ************************************** // + template + HDA_OfstreamWrapper & operator <<(T const &elem){ + if(hasWrittenSomething){ + ofs << sep << elem; + } + else{ + ofs << elem; + hasWrittenSomething = true; + } + return *this; + } + + HDA_OfstreamWrapper & operator <<(std::vector const &elem){ + ofs << elem[0]; + for(size_t i = 1 ; i < elem.size(); ++i){ + ofs << sep << elem[i]; + } + ofs << "\n"; + return *this; + } + +}; + +}} +#endif \ No newline at end of file diff --git a/src/dataanalytics/HDA_PulseRecorder.cpp b/src/dataanalytics/HDA_PulseRecorder.cpp index 53981ab78..fcb6e9151 100644 --- a/src/dataanalytics/HDA_PulseRecorder.cpp +++ b/src/dataanalytics/HDA_PulseRecorder.cpp @@ -8,28 +8,45 @@ using namespace helios::analytics; // ************************** // bool HDA_PulseRecorder::isAnyBufferOpen(){ bool anyOpen = false; - anyOpen |= incidenceAngle_rad->isOpen(); + anyOpen |= intensityCalc->isOpen(); return anyOpen; } void HDA_PulseRecorder::openBuffers(){ // Open subray related buffers - incidenceAngle_rad = std::make_shared>( - craftOutputPath("incidence_angle_rad.csv") + size_t const maxSize = 256; + std::string const sep = ","; + intensityCalc = std::make_shared>>( + craftOutputPath("intensity_calc.csv"), + maxSize, + sep, + true // vectorial flag ); } void HDA_PulseRecorder::closeBuffers(){ // Close subray buffers - incidenceAngle_rad->close(); + std::unique_lock lock(intensityCalcMutex); + intensityCalc->close(); } // *** RECORD METHODS *** // // ************************ // -void HDA_PulseRecorder::recordIncidenceAngle(double const _incidenceAngle_rad){ - std::unique_lock lock(incidenceAngle_rad_mutex); - incidenceAngle_rad->push(_incidenceAngle_rad); +void HDA_PulseRecorder::recordIntensityCalculation( + double const incidenceAngle_rad, + double const targetRange_m, + double const targetArea_m2, + double const radius_m, + double const bdrf, + double const crossSection, + double const receivedPower +){ + std::unique_lock lock(intensityCalcMutex); + intensityCalc->push(std::vector({ + incidenceAngle_rad, targetRange_m, targetArea_m2, radius_m, bdrf, + crossSection, receivedPower + })); } #endif diff --git a/src/dataanalytics/HDA_PulseRecorder.h b/src/dataanalytics/HDA_PulseRecorder.h index e3b9a792f..1fa1f20f2 100644 --- a/src/dataanalytics/HDA_PulseRecorder.h +++ b/src/dataanalytics/HDA_PulseRecorder.h @@ -23,14 +23,32 @@ class HDA_PulseRecorder : public HDA_Recorder{ // *** ATTRIBUTES *** // // ******************** // /** - * @brief The record buffer for the incidence angles (in radians). + * @brief The vector which components are variables involved on a + * particular intensity calculation for a given subray. + * + * [0] -> Incidence angle in radians. + * + * [1] -> The target range in meters, i.e., the distance between the beam's + * origin and the intersection point. + * + * [2] -> The target area in squared meters. + * + * [3] -> The radius in meters, i.e., the distance between the beam's + * center line and the intersection point. + * + * [4] -> The bidirectional reflectance function (BDRF). + * + * [5] -> The cross-section in squared meters. + * + * [6] -> The calculated received power, i.e., intensity. */ - std::shared_ptr> incidenceAngle_rad; + std::shared_ptr>> intensityCalc; + /** - * @brief The mutex to handle concurrent writes to the incidenceAngle_rad - * record buffer. + * @brief The mutex to handle concurrent writes to the buffers related to + * intensity calculation. */ - std::mutex incidenceAngle_rad_mutex; + std::mutex intensityCalcMutex; public: // *** CONSTRUCTION / DESTRUCTION *** // @@ -74,7 +92,15 @@ class HDA_PulseRecorder : public HDA_Recorder{ /** * @brief Handle all the records for the current simulation step. */ - virtual void recordIncidenceAngle(double const incidenceAngle_rad); + virtual void recordIntensityCalculation( + double const incidenceAngle_rad, + double const targetRange_m, + double const targetArea_m2, + double const radius_m, + double const bdrf, + double const crossSection, + double const receivedPower + ); }; diff --git a/src/dataanalytics/HDA_RecordBuffer.h b/src/dataanalytics/HDA_RecordBuffer.h index 10283743d..6ee1de8ff 100644 --- a/src/dataanalytics/HDA_RecordBuffer.h +++ b/src/dataanalytics/HDA_RecordBuffer.h @@ -1,6 +1,8 @@ #ifdef DATA_ANALYTICS #pragma once +#include + #include #include #include @@ -34,18 +36,9 @@ class HDA_RecordBuffer { */ std::string outpath; /** - * @brief The output stream to write the contents of the buffer - */ - std::ofstream ofs; - /** - * @brief The separator between recorded elements - */ - std::string sep; - /** - * @brief The function to write the content of the buffer through the - * output stream + * @brief The wrapped output stream to write the contents of the buffer */ - std::function write; + HDA_OfstreamWrapper ofsw; public: // *** CONSTRUCTION / DESTRUCTION *** // @@ -59,15 +52,13 @@ class HDA_RecordBuffer { HDA_RecordBuffer( std::string const &outpath, size_t const maxSize=256, - std::string const &sep="," + std::string const &sep=",", + bool const vectorial=false ) : maxSize(maxSize), outpath(outpath), - ofs(outpath, std::ios_base::out), - sep(sep) - { - write = [&](void) -> void {this->firstWrite();}; - } + ofsw(outpath, sep) + {} virtual ~HDA_RecordBuffer(){ if(isOpen()) close(); @@ -80,32 +71,17 @@ class HDA_RecordBuffer { * not * @return True if the output stream is opened, false otherwise */ - inline bool isOpen() {return ofs.is_open();} - /** - * @brief Write the contents of the buffer through the output stream for - * the first time - */ - inline void firstWrite() { - size_t numElems = buff.size(); - ofs << buff[0]; - for(size_t i = 1 ; i < numElems ; ++i){ - ofs << sep << buff[i]; - } - this->write = [&] (void) -> void {this->nextWrite();}; - } + inline bool isOpen() {return ofsw.is_open();} /** - * @brief Write the contents of the buffer through the output stream after - * the first time + * @brief Method to write the elements of the buffer to a file. */ - inline void nextWrite() { - for(T const & elem : buff) ofs << sep << elem; - } + inline void write() {for(T const & elem : buff) ofsw << elem;} /** * @brief Write all the contents of the buffer and then make it empty */ inline void flush(){ if(buff.size() > 0){ - this->write(); + write(); buff.clear(); } } @@ -115,7 +91,7 @@ class HDA_RecordBuffer { */ inline void close(){ flush(); - if(isOpen()) ofs.close(); + if(isOpen()) ofsw.close(); } /** * @brief Insert given element in the buffer. If the buffer is full, it diff --git a/src/main/helios_version.cpp b/src/main/helios_version.cpp index d9e40f4bd..481e9f2cb 100644 --- a/src/main/helios_version.cpp +++ b/src/main/helios_version.cpp @@ -4,7 +4,7 @@ const char * HELIOS_VERSION = "1.2.0"; -const char * HELIOS_GIT_HASH = "4eab409c"; +const char * HELIOS_GIT_HASH = "9f5ba7f6"; const char * getHeliosVersion(){ return HELIOS_VERSION; diff --git a/src/scanner/MultiScanner.cpp b/src/scanner/MultiScanner.cpp index 85c455774..6d07e9526 100644 --- a/src/scanner/MultiScanner.cpp +++ b/src/scanner/MultiScanner.cpp @@ -212,6 +212,9 @@ double MultiScanner::calcIntensity( double const targetArea, double const radius, size_t const idx +#ifdef DATA_ANALYTICS + ,std::shared_ptr pulseRecorder +#endif ) const{ return scanDevs[idx].calcIntensity( incidenceAngle, @@ -219,6 +222,9 @@ double MultiScanner::calcIntensity( mat, targetArea, radius +#ifdef DATA_ANALYTICS + ,pulseRecorder +#endif ); } diff --git a/src/scanner/MultiScanner.h b/src/scanner/MultiScanner.h index 2b9cf43b8..37bab0cb6 100644 --- a/src/scanner/MultiScanner.h +++ b/src/scanner/MultiScanner.h @@ -196,6 +196,9 @@ class MultiScanner : public Scanner{ double const targetArea, double const radius, size_t const idx +#ifdef DATA_ANALYTICS + ,std::shared_ptr pulseRecorder +#endif ) const override; /** * @see Scanner::calcIntensity diff --git a/src/scanner/Scanner.h b/src/scanner/Scanner.h index c27a091c1..922737de4 100644 --- a/src/scanner/Scanner.h +++ b/src/scanner/Scanner.h @@ -499,6 +499,9 @@ class Scanner : public Asset { double const targetArea, double const radius, size_t const idx +#ifdef DATA_ANALYTICS + ,std::shared_ptr pulseRecorder +#endif ) const = 0; /** * @brief Handle to which scanning device request the intensity computation diff --git a/src/scanner/ScanningDevice.cpp b/src/scanner/ScanningDevice.cpp index 085196463..b383d0728 100644 --- a/src/scanner/ScanningDevice.cpp +++ b/src/scanner/ScanningDevice.cpp @@ -322,6 +322,9 @@ double ScanningDevice::calcIntensity( Material const &mat, double const targetArea, double const radius +#ifdef DATA_ANALYTICS + ,std::shared_ptr pulseRecorder +#endif ) const { double bdrf = 0, sigma = 0; if(mat.isPhong()) { @@ -353,7 +356,7 @@ double ScanningDevice::calcIntensity( << mat.name << "\""; logging::ERR(ss.str()); } - return EnergyMaths::calcReceivedPower( + double const receivedPower = EnergyMaths::calcReceivedPower( averagePower_w, wavelength_m, targetRange, @@ -366,6 +369,13 @@ double ScanningDevice::calcIntensity( atmosphericExtinction, sigma ) * 1000000000.0; +#ifdef DATA_ANALYTICS + pulseRecorder->recordIntensityCalculation( + incidenceAngle, targetRange, targetArea, radius, bdrf, sigma, + receivedPower + ); +#endif + return receivedPower; } double ScanningDevice::calcIntensity( double const targetRange, diff --git a/src/scanner/ScanningDevice.h b/src/scanner/ScanningDevice.h index c30be2321..69e0c557b 100644 --- a/src/scanner/ScanningDevice.h +++ b/src/scanner/ScanningDevice.h @@ -11,6 +11,10 @@ class AbstractDetector; #include #include #include +#ifdef DATA_ANALYTICS +#include +using helios::analytics::HDA_PulseRecorder; +#endif #include @@ -377,6 +381,9 @@ class ScanningDevice : public Asset { Material const &mat, double const targetArea, double const radius +#ifdef DATA_ANALYTICS + ,std::shared_ptr pulseRecorder +#endif ) const; /** diff --git a/src/scanner/SingleScanner.cpp b/src/scanner/SingleScanner.cpp index a7dd9dd7b..df9bb25d5 100644 --- a/src/scanner/SingleScanner.cpp +++ b/src/scanner/SingleScanner.cpp @@ -248,6 +248,9 @@ double SingleScanner::calcIntensity( double const targetArea, double const radius, size_t const idx +#ifdef DATA_ANALYTICS + ,std::shared_ptr pulseRecorder +#endif ) const { return scanDev.calcIntensity( incidenceAngle, @@ -255,6 +258,9 @@ double SingleScanner::calcIntensity( mat, targetArea, radius +#ifdef DATA_ANALYTICS + ,pulseRecorder +#endif ); } double SingleScanner::calcIntensity( diff --git a/src/scanner/SingleScanner.h b/src/scanner/SingleScanner.h index a21b6043d..c565df7c1 100644 --- a/src/scanner/SingleScanner.h +++ b/src/scanner/SingleScanner.h @@ -169,6 +169,9 @@ class SingleScanner : public Scanner{ double const targetArea, double const radius, size_t const idx +#ifdef DATA_ANALYTICS + ,std::shared_ptr pulseRecorder +#endif ) const override; /** * @see Scanner::calcIntensity diff --git a/src/scanner/detector/FullWaveformPulseRunnable.cpp b/src/scanner/detector/FullWaveformPulseRunnable.cpp index fbbb0b561..20f4adb81 100644 --- a/src/scanner/detector/FullWaveformPulseRunnable.cpp +++ b/src/scanner/detector/FullWaveformPulseRunnable.cpp @@ -173,9 +173,6 @@ void FullWaveformPulseRunnable::handleSubray( subrayDirection, intersect->point ); -#ifdef DATA_ANALYTICS - pulseRecorder->recordIncidenceAngle(incidenceAngle); -#endif } // Distance between beam origin and intersection: @@ -211,6 +208,9 @@ void FullWaveformPulseRunnable::handleSubray( targetArea, radius, pulse.getDeviceIndex() +#ifdef DATA_ANALYTICS + ,pulseRecorder +#endif ); }