Commit f789f3d8 authored by Giovanni La Mura's avatar Giovanni La Mura
Browse files

Implement dynamic range plotting option

parent a5df49ae
Loading
Loading
Loading
Loading
+129 −36
Original line number Diff line number Diff line
@@ -21,10 +21,86 @@
#  The script execution requires python3.

import cmath
import math
import os

from sys import argv, stdout

## \brief Class to represent the dynamic range memory structure.
#
# In order to implement a light-weight test that is able to choose
# whether to produce a text-only output or a text + diagnostic plot
# output, the `PlotData` class stores the memory structures to
# produce the text log and the plots. The data for the plots are
# filled with dummy place-holders if the required output is text
# only, while they are filled with actual data, otherwise.
#
# \returns exit_code: `int` 0 on successful completion.
class PlotData:
    # \brief PlotData instance constructor.
    def __init__(self):
        self.max_real = -1.0
        self.max_imag = -1.0
        self.max_absl = -1.0
        self.min_real = 1.0
        self.min_imag = 1.0
        self.sml_absl = 1.0
        self.sml_real = 1.0
        self.sml_imag = 1.0
        self.absl_hist = [0 for i in range(-99, 100)]
        self.real_hist = [0 for i in range(-99, 100)]
        self.imag_hist = [0 for i in range(-99, 100)]
        self.max_real_mag = -100
        self.min_real_mag = 100
        self.max_imag_mag = -100
        self.min_imag_mag = 100
        self.max_absl_mag = -100
        self.min_absl_mag = 100

    # \brief Print a text log of the dynamic range.
    def log_dynamic_range(self):
        print("        MAX( ABS[AM] ) = %14.7e"%self.max_absl)
        print("        MIN( ABS[AM] ) = %14.7e"%self.sml_absl)
        print("       MAX( REAL[AM] ) = %14.7e"%self.max_real)
        print("       MIN( REAL[AM] ) = %14.7e"%self.min_real)
        print("       MAX( IMAG[AM] ) = %14.7e"%self.max_imag)
        print("       MIN( IMAG[AM] ) = %14.7e"%self.min_imag)
        print("MIN( ABS( REAL[AM] ) ) = %14.7e"%self.sml_real)
        print("MIN( ABS( IMAG[AM] ) ) = %14.7e"%self.sml_imag)
        return

    # \brief Make histograms of dynamic range with matplotlib.
    def plot_dynamic_range(self, config):
        import matplotlib.pyplot as plt
        import numpy as np
        self.absl_hist = np.array(self.absl_hist)
        self.real_hist = np.array(self.real_hist)
        self.imag_hist = np.array(self.imag_hist)
        vec_x_pos = np.arange(-98.5, 100.0, 1.0)
        fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, ncols=1)
        ax1.bar(vec_x_pos, self.absl_hist, color = "grey", label = "Abs. values")
        ax1.set_xlim(self.min_absl_mag - 1, self.max_absl_mag + 1)
        ax1.set_xlabel("Order of magnitude")
        ax1.set_ylabel("Element counts")
        ax1.legend(loc = "best")
        ax2.bar(vec_x_pos, self.real_hist, color = "red", label = "Real values")
        ax2.set_xlim(self.min_real_mag - 1, self.max_real_mag + 1)
        ax2.set_xlabel("Order of magnitude")
        ax2.set_ylabel("Element counts")
        ax2.legend(loc = "best")
        ax3.bar(vec_x_pos, self.imag_hist, color = "blue", label = "Imag. values")
        ax3.set_xlim(self.min_imag_mag - 1, self.max_imag_mag + 1)
        ax3.set_xlabel("Order of magnitude")
        ax3.set_ylabel("Element counts")
        ax3.legend(loc = "best")
        if (config['log_plot_y']):
            ax1.set_yscale("log")
            ax2.set_yscale("log")
            ax3.set_yscale("log")
        plt.tight_layout()
        plt.show()
        return

## \brief Main execution code
#
# `main()` is the function that handles the creation of the script configuration
@@ -52,14 +128,7 @@ def main():
def get_dynamic_range(config):
    result = 0
    num_read_lines = 0
    max_real = -1.0
    max_imag = -1.0
    max_absl = -1.0
    min_real = 1.0
    min_imag = 1.0
    sml_absl = 1.0
    sml_real = 1.0
    sml_imag = 1.0
    pd = PlotData()
    stdout.write("INFO: scanning data file. Please, wait...")
    stdout.flush()
    matrix_file = open(config['matrix_name'], 'r')
@@ -71,18 +140,39 @@ def get_dynamic_range(config):
        split_value = str_value.split(",")
        real = float(split_value[0])
        imag = float(split_value[1])
        if (real > max_real): max_real = real
        if (imag > max_imag): max_imag = imag
        if (real < min_real): min_real = real
        if (imag < min_imag): min_imag = imag
        if (real > pd.max_real): pd.max_real = real
        #    if (config['make_plots'] and real != 0.0):
        #        mag_value = int(math.log10(abs(real)).floor())
        #        if (mag_value > pd.max_real_mag): pd.max_real_mag = mag_value
        #        if (mag_value < pd.min_real_mag): pd.min_real_mag = mag_value
        #        pd.real_hist[mag_value + 99] += 1
        if (imag > pd.max_imag): pd.max_imag = imag
        if (real < pd.min_real): pd.min_real = real
        if (imag < pd.min_imag): pd.min_imag = imag
        cvalue = complex(real, imag)
        absl_val = abs(cvalue)
        if (absl_val > max_absl): max_absl = absl_val
        if (absl_val < sml_absl): sml_absl = absl_val if absl_val > 0.0 else sml_absl
        if (absl_val > pd.max_absl): pd.max_absl = absl_val
        if (absl_val < pd.sml_absl): pd.sml_absl = absl_val if absl_val > 0.0 else pd.sml_absl
        if (real < 0): real *= -1.0
        if (imag < 0): imag *= -1.0
        if (real < sml_real): sml_real = real if real > 0.0 else sml_real
        if (imag < sml_imag): sml_imag = imag if imag > 0.0 else sml_real
        if (real < pd.sml_real): pd.sml_real = real if real > 0.0 else pd.sml_real
        if (imag < pd.sml_imag): pd.sml_imag = imag if imag > 0.0 else pd.sml_real
        if (config['make_plots']):
            if (real > 0.0):
                mag_value = int(math.floor(math.log10(real)))
                if (mag_value > pd.max_real_mag): pd.max_real_mag = mag_value
                if (mag_value < pd.min_real_mag): pd.min_real_mag = mag_value
                pd.real_hist[mag_value + 99] += 1
            if (imag > 0.0):
                mag_value = int(math.floor(math.log10(imag)))
                if (mag_value > pd.max_imag_mag): pd.max_imag_mag = mag_value
                if (mag_value < pd.min_imag_mag): pd.min_imag_mag = mag_value
                pd.imag_hist[mag_value + 99] += 1
            if (absl_val > 0.0):
                mag_value = int(math.floor(math.log10(absl_val)))
                if (mag_value > pd.max_absl_mag): pd.max_absl_mag = mag_value
                if (mag_value < pd.min_absl_mag): pd.min_absl_mag = mag_value
                pd.absl_hist[mag_value + 99] += 1
        str_line = matrix_file.readline()
        if (config['limit'] > 0):
            num_read_lines += 1
@@ -90,14 +180,9 @@ def get_dynamic_range(config):
                str_line = "" # Close the while loop
    matrix_file.close()
    print(" done!")
    print("        MAX( ABS[AM] ) = %14.7e"%max_absl)
    print("        MIN( ABS[AM] ) = %14.7e"%sml_absl)
    print("       MAX( REAL[AM] ) = %14.7e"%max_real)
    print("       MIN( REAL[AM] ) = %14.7e"%min_real)
    print("       MAX( IMAG[AM] ) = %14.7e"%max_imag)
    print("       MIN( IMAG[AM] ) = %14.7e"%min_imag)
    print("MIN( ABS( REAL[AM] ) ) = %14.7e"%sml_real)
    print("MIN( ABS( IMAG[AM] ) ) = %14.7e"%sml_imag)
    pd.log_dynamic_range()
    if (config['make_plots']):
        pd.plot_dynamic_range(config)
    return result

## \brief Parse the command line arguments.
@@ -111,9 +196,11 @@ def get_dynamic_range(config):
#  \returns config: `dict` A dictionary containing the script configuration.
def parse_arguments():
    config = {
        'matrix_name': "",
        'help_mode': False,
        'limit': -1,
        'log_plot_y': True,
        'make_plots': False,
        'matrix_name': "",
    }
    for arg in argv[1:]:
        if (arg.startswith("--help")):
@@ -121,6 +208,10 @@ def parse_arguments():
        elif (arg.startswith("--limit=")):
            split_arg = arg.split('=')
            config['limit'] = int(split_arg[1])
        elif (arg.startswith("--lin-y")):
            config['log_plot_y'] = False
        elif (arg.startswith("--make-plots")):
            config['make_plots'] = True
        else:
            if (os.path.isfile(arg)):
                config['matrix_name'] = arg
@@ -131,7 +222,7 @@ def parse_arguments():
## \brief Print a command-line help summary.
def print_help():
    print("                                                                        ")
    print("***             PYDYNRANGE               ***")
    print("****************************   PYDYNRANGE   ****************************")
    print("                                                                        ")
    print("Get the dynamic range of a complex matrix.                              ")
    print("                                                                        ")
@@ -140,6 +231,8 @@ def print_help():
    print("Valid options are:                                                      ")
    print("--help                                         Print this help and exit.")
    print("--limit=NUMBER                             Check only NUMBER file lines.")
    print("--lin-y                                 Use linear scale on plot y-axes.")
    print("--make-plots        Plot histograms of magnitudes (requires matplotlib).")
    print("                                                                        ")