From ff4938702ef305f2ac527d6575873bf1a366f1ad Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 21 Oct 2017 13:05:51 +0200 Subject: [PATCH] Add Gnuplot-based plot results for FFT MeasureExecutionTime test --- src/tests/CMakeLists.txt | 5 + src/tests/common-files/gnuplot_i.h | 1953 +++++++++++++++++ .../unit-tests/arithmetic/fft_length_test.cc | 70 +- 3 files changed, 2025 insertions(+), 3 deletions(-) create mode 100644 src/tests/common-files/gnuplot_i.h diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index f37753413..651713998 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -158,6 +158,11 @@ if(ENABLE_FPGA) add_definitions(-DFPGA_BLOCKS_TEST=1) endif(ENABLE_FPGA) +find_package(Gnuplot) +if(GNUPLOT_FOUND) + add_definitions(-DGNUPLOT_EXECUTABLE="${GNUPLOT_EXECUTABLE}") +endif(GNUPLOT_FOUND) + ################################################################################ # Optional generator ################################################################################ diff --git a/src/tests/common-files/gnuplot_i.h b/src/tests/common-files/gnuplot_i.h new file mode 100644 index 000000000..615e9084e --- /dev/null +++ b/src/tests/common-files/gnuplot_i.h @@ -0,0 +1,1953 @@ +/*! + * \file gnuplot_i.h + * \brief A C++ interface to gnuplot. + * \author Carles Fernandez-Prades, 2017. cfernandez(at)cttc.es + * + * Source code found at https://code.google.com/archive/p/gnuplot-cpp/ + * by Jeremy Conlin jeremit0(at)gmail.com + * + * Version history: + * 0. C interface + * by N. Devillard (27/01/03) + * 1. C++ interface: direct translation from the C interface + * by Rajarshi Guha (07/03/03) + * 2. corrections for Win32 compatibility + * by V. Chyzhdzenka (20/05/03) + * 3. some member functions added, corrections for Win32 and Linux + * compatibility + * by M. Burgis (10/03/08) + * ------------------------------------------------------------------------- + * + * Copyright (C) 2013-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_GNUPLOT_I_H_ +#define GNSS_SDR_GNUPLOT_I_H_ + + +#include +#include +#include +#include +#include // for std::ostringstream +#include +#include +#include // for getenv() +#include // for std::list + + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) +//defined for 32 and 64-bit environments + #include // for _access(), _mktemp() + #define GP_MAX_TMP_FILES 27 // 27 temporary files it's Microsoft restriction +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) +//all UNIX-like OSs (Linux, *BSD, MacOSX, Solaris, ...) + #include // for access(), mkstemp() + #define GP_MAX_TMP_FILES 64 +#else + #error unsupported or unknown operating system +#endif + +//declare classes in global namespace + + +class GnuplotException : public std::runtime_error +{ +public: + GnuplotException(const std::string &msg) : std::runtime_error(msg){} +}; + + + +class Gnuplot +{ +private: + //---------------------------------------------------------------------------------- + // member data + ///\brief pointer to the stream that can be used to write to the pipe + FILE *gnucmd; + ///\brief validation of gnuplot session + bool valid; + ///\brief true = 2d, false = 3d + bool two_dim; + ///\brief number of plots in session + int nplots; + ///\brief functions and data are displayed in a defined styles + std::string pstyle; + ///\brief interpolate and approximate data in defined styles (e.g. spline) + std::string smooth; + ///\brief list of created tmpfiles + std::vector tmpfile_list; + + //---------------------------------------------------------------------------------- + // static data + ///\brief number of all tmpfiles (number of tmpfiles restricted) + static int tmpfile_num; + ///\brief name of executed GNUPlot file + static std::string m_sGNUPlotFileName; + ///\brief gnuplot path + static std::string m_sGNUPlotPath; + ///\brief standart terminal, used by showonscreen + static std::string terminal_std; + + //---------------------------------------------------------------------------------- + // member functions (auxiliary functions) + // --------------------------------------------------- + ///\brief get_program_path(); and popen(); + /// + /// \param --> void + /// + /// \return <-- void + // --------------------------------------------------- + void init(); + // --------------------------------------------------- + ///\brief creates tmpfile and returns its name + /// + /// \param tmp --> points to the tempfile + /// + /// \return <-- the name of the tempfile + // --------------------------------------------------- + std::string create_tmpfile(std::ofstream &tmp); + + //---------------------------------------------------------------------------------- + ///\brief gnuplot path found? + /// + /// \param --- + /// + /// \return <-- found the gnuplot path (yes == true, no == false) + // --------------------------------------------------------------------------------- + static bool get_program_path(); + + // --------------------------------------------------------------------------------- + ///\brief checks if file is available + /// + /// \param filename --> the filename + /// \param mode --> the mode [optional,default value = 0] + /// + /// \return file exists (yes == true, no == false) + // --------------------------------------------------------------------------------- + bool file_available(const std::string &filename); + + // --------------------------------------------------------------------------------- + ///\brief checks if file exists + /// + /// \param filename --> the filename + /// \param mode --> the mode [optional,default value = 0] + /// + /// \return file exists (yes == true, no == false) + // --------------------------------------------------------------------------------- + static bool file_exists(const std::string &filename, int mode=0); + +public: + // ---------------------------------------------------------------------------- + /// \brief optional function: set Gnuplot path manual + /// attention: for windows: path with slash '/' not backslash '\' + /// + /// \param path --> the gnuplot path + /// + /// \return true on success, false otherwise + // ---------------------------------------------------------------------------- + static bool set_GNUPlotPath(const std::string &path); + + // ---------------------------------------------------------------------------- + /// optional: set standart terminal, used by showonscreen + /// defaults: Windows - win, Linux - x11, Mac - aqua + /// + /// \param type --> the terminal type + /// + /// \return --- + // ---------------------------------------------------------------------------- + static void set_terminal_std(const std::string &type); + + //----------------------------------------------------------------------------- + // constructors + // ---------------------------------------------------------------------------- + + ///\brief set a style during construction + Gnuplot(const std::string &style = "points"); + + /// plot a single std::vector at one go + Gnuplot(const std::vector &x, + const std::string &title = "", + const std::string &style = "points", + const std::string &labelx = "x", + const std::string &labely = "y"); + + /// plot pairs std::vector at one go + Gnuplot(const std::vector &x, + const std::vector &y, + const std::string &title = "", + const std::string &style = "points", + const std::string &labelx = "x", + const std::string &labely = "y"); + + /// plot triples std::vector at one go + Gnuplot(const std::vector &x, + const std::vector &y, + const std::vector &z, + const std::string &title = "", + const std::string &style = "points", + const std::string &labelx = "x", + const std::string &labely = "y", + const std::string &labelz = "z"); + + /// destructor: needed to delete temporary files + ~Gnuplot(); + + //---------------------------------------------------------------------------------- + + /// send a command to gnuplot + Gnuplot& cmd(const std::string &cmdstr); + + // --------------------------------------------------------------------------------- + ///\brief Sends a command to an active gnuplot session, identical to cmd() + /// send a command to gnuplot using the << operator + /// + /// \param cmdstr --> the command string + /// + /// \return <-- a reference to the gnuplot object + // --------------------------------------------------------------------------------- + inline Gnuplot& operator<<(const std::string &cmdstr){ + cmd(cmdstr); + return(*this); + } + + //---------------------------------------------------------------------------------- + // show on screen or write to file + + /// sets terminal type to terminal_std + Gnuplot& showonscreen(); // window output is set by default (win/x11/aqua) + + /// saves a gnuplot session to a postscript file, filename without extension + Gnuplot& savetops(const std::string &filename = "gnuplot_output"); + + //---------------------------------------------------------------------------------- + // set and unset + + /// set line style (some of these styles require additional information): + /// lines, points, linespoints, impulses, dots, steps, fsteps, histeps, + /// boxes, histograms, filledcurves + Gnuplot& set_style(const std::string &stylestr = "points"); + + /// interpolation and approximation of data, arguments: + /// csplines, bezier, acsplines (for data values > 0), sbezier, unique, frequency + /// (works only with plot_x, plot_xy, plotfile_x, plotfile_xy + /// (if smooth is set, set_style has no effekt on data plotting) + Gnuplot& set_smooth(const std::string &stylestr = "csplines"); + + // ---------------------------------------------------------------------- + /// \brief unset smooth + /// attention: smooth is not set by default + /// + /// \param --- + /// + /// \return <-- a reference to a gnuplot object + // ---------------------------------------------------------------------- + inline Gnuplot& unset_smooth(){ smooth = ""; return *this;}; + + /// scales the size of the points used in plots + Gnuplot& set_pointsize(const double pointsize = 1.0); + + /// turns grid on/off + inline Gnuplot& set_grid() {cmd("set grid");return *this;}; + /// grid is not set by default + inline Gnuplot& unset_grid(){cmd("unset grid");return *this;}; + + // ----------------------------------------------- + /// set the mulitplot mode + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot& set_multiplot(){cmd("set multiplot") ;return *this;}; + + // ----------------------------------------------- + /// unsets the mulitplot mode + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot& unset_multiplot(){cmd("unset multiplot");return *this;}; + + /// set sampling rate of functions, or for interpolating data + Gnuplot& set_samples(const int samples = 100); + /// set isoline density (grid) for plotting functions as surfaces (for 3d plots) + Gnuplot& set_isosamples(const int isolines = 10); + + // -------------------------------------------------------------------------- + /// enables/disables hidden line removal for surface plotting (for 3d plot) + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // -------------------------------------------------------------------------- + Gnuplot& set_hidden3d(){cmd("set hidden3d");return *this;}; + + // --------------------------------------------------------------------------- + /// hidden3d is not set by default + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // --------------------------------------------------------------------------- + inline Gnuplot& unset_hidden3d(){cmd("unset hidden3d"); return *this;}; + + /// enables/disables contour drawing for surfaces (for 3d plot) + /// base, surface, both + Gnuplot& set_contour(const std::string &position = "base"); + // -------------------------------------------------------------------------- + /// contour is not set by default, it disables contour drawing for surfaces + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ------------------------------------------------------------------ + inline Gnuplot& unset_contour(){cmd("unset contour");return *this;}; + + // ------------------------------------------------------------ + /// enables/disables the display of surfaces (for 3d plot) + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ------------------------------------------------------------------ + inline Gnuplot& set_surface(){cmd("set surface");return *this;}; + + // ---------------------------------------------------------- + /// surface is set by default, + /// it disables the display of surfaces (for 3d plot) + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ------------------------------------------------------------------ + inline Gnuplot& unset_surface(){cmd("unset surface"); return *this;} + + + /// switches legend on/off + /// position: inside/outside, left/center/right, top/center/bottom, nobox/box + Gnuplot& set_legend(const std::string &position = "default"); + + // ------------------------------------------------------------------ + /// \brief Switches legend off + /// attention:legend is set by default + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ------------------------------------------------------------------ + inline Gnuplot& unset_legend(){cmd("unset key"); return *this;} + + // ----------------------------------------------------------------------- + /// \brief sets and clears the title of a gnuplot session + /// + /// \param title --> the title of the plot [optional, default == ""] + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------------------------------- + inline Gnuplot& set_title(const std::string &title = "") + { + std::string cmdstr; + cmdstr = "set title \""; + cmdstr+=title; + cmdstr+="\""; + *this<set_title();return *this;} + + /// set x axis label + Gnuplot& set_ylabel(const std::string &label = "x"); + /// set y axis label + Gnuplot& set_xlabel(const std::string &label = "y"); + /// set z axis label + Gnuplot& set_zlabel(const std::string &label = "z"); + + /// set axis - ranges + Gnuplot& set_xrange(const double iFrom, + const double iTo); + /// set y-axis - ranges + Gnuplot& set_yrange(const double iFrom, + const double iTo); + /// set z-axis - ranges + Gnuplot& set_zrange(const double iFrom, + const double iTo); + /// autoscale axis (set by default) of xaxis + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot& set_xautoscale(){cmd("set xrange restore");cmd("set autoscale x");return *this;}; + + // ----------------------------------------------- + /// autoscale axis (set by default) of yaxis + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot& set_yautoscale(){cmd("set yrange restore");cmd("set autoscale y");return *this;}; + + // ----------------------------------------------- + /// autoscale axis (set by default) of zaxis + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot& set_zautoscale(){cmd("set zrange restore");cmd("set autoscale z");return *this;}; + + /// turns on/off log scaling for the specified xaxis (logscale is not set by default) + Gnuplot& set_xlogscale(const double base = 10); + /// turns on/off log scaling for the specified yaxis (logscale is not set by default) + Gnuplot& set_ylogscale(const double base = 10); + /// turns on/off log scaling for the specified zaxis (logscale is not set by default) + Gnuplot& set_zlogscale(const double base = 10); + + // ----------------------------------------------- + /// turns off log scaling for the x axis + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot& unset_xlogscale(){cmd("unset logscale x"); return *this;}; + + // ----------------------------------------------- + /// turns off log scaling for the y axis + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot& unset_ylogscale(){cmd("unset logscale y"); return *this;}; + + // ----------------------------------------------- + /// turns off log scaling for the z axis + /// + /// \param --- + /// + /// \return <-- reference to the gnuplot object + // ----------------------------------------------- + inline Gnuplot& unset_zlogscale(){cmd("unset logscale z"); return *this;}; + + /// set palette range (autoscale by default) + Gnuplot& set_cbrange(const double iFrom, const double iTo); + + //---------------------------------------------------------------------------------- + // plot + + /// plot a single std::vector: x + /// from file + Gnuplot& plotfile_x(const std::string &filename, + const unsigned int column = 1, + const std::string &title = ""); + + /// from std::vector + template + Gnuplot& plot_x(const X& x, const std::string &title = ""); + + /// plot x,y pairs: x y + /// from file + Gnuplot& plotfile_xy(const std::string &filename, + const unsigned int column_x = 1, + const unsigned int column_y = 2, + const std::string &title = ""); + /// from data + template + Gnuplot& plot_xy(const X& x, const Y& y, const std::string &title = ""); + + /// plot x,y pairs with dy errorbars: x y dy + /// from file + Gnuplot& plotfile_xy_err(const std::string &filename, + const unsigned int column_x = 1, + const unsigned int column_y = 2, + const unsigned int column_dy = 3, + const std::string &title = ""); + /// from data + template + Gnuplot& plot_xy_err(const X &x, const Y &y, const E &dy, + const std::string &title = ""); + + /// plot x,y,z triples: x y z + /// from file + Gnuplot& plotfile_xyz(const std::string &filename, + const unsigned int column_x = 1, + const unsigned int column_y = 2, + const unsigned int column_z = 3, + const std::string &title = ""); + /// from std::vector + template + Gnuplot& plot_xyz(const X &x, + const Y &y, + const Z &z, + const std::string &title = ""); + + /// plot an equation of the form: y = ax + b, you supply a and b + Gnuplot& plot_slope(const double a, + const double b, + const std::string &title = ""); + + /// plot an equation supplied as a std::string y=f(x), write only the function f(x) not y= + /// the independent variable has to be x + /// binary operators: ** exponentiation, * multiply, / divide, + add, - substract, % modulo + /// unary operators: - minus, ! factorial + /// elementary functions: rand(x), abs(x), sgn(x), ceil(x), floor(x), int(x), imag(x), real(x), arg(x), + /// sqrt(x), exp(x), log(x), log10(x), sin(x), cos(x), tan(x), asin(x), acos(x), atan(x), atan2(y,x), + /// sinh(x), cosh(x), tanh(x), asinh(x), acosh(x), atanh(x) + /// special functions: erf(x), erfc(x), inverf(x), gamma(x), igamma(a,x), lgamma(x), ibeta(p,q,x), + /// besj0(x), besj1(x), besy0(x), besy1(x), lambertw(x) + /// statistical fuctions: norm(x), invnorm(x) + Gnuplot& plot_equation(const std::string &equation, + const std::string &title = ""); + + /// plot an equation supplied as a std::string z=f(x,y), write only the function f(x,y) not z= + /// the independent variables have to be x and y + Gnuplot& plot_equation3d(const std::string &equation, + const std::string &title = ""); + + /// plot image + Gnuplot& plot_image(const unsigned char *ucPicBuf, + const unsigned int iWidth, + const unsigned int iHeight, + const std::string &title = ""); + + //---------------------------------------------------------------------------------- + ///\brief replot repeats the last plot or splot command. + /// this can be useful for viewing a plot with different set options, + /// or when generating the same plot for several devices (showonscreen, savetops) + /// + /// \param --- + /// + /// \return --- + //---------------------------------------------------------------------------------- + inline Gnuplot& replot(void){if (nplots > 0) cmd("replot");return *this;}; + + /// resets a gnuplot session (next plot will erase previous ones) + Gnuplot& reset_plot(); + + /// resets a gnuplot session and sets all variables to default + Gnuplot& reset_all(); + + /// deletes temporary files + void remove_tmpfiles(); + + // ------------------------------------------------------------------- + /// \brief Is the gnuplot session valid ?? + /// + /// + /// \param --- + /// + /// \return true if valid, false if not + // ------------------------------------------------------------------- + inline bool is_valid(){return(valid);}; +}; + + +//------------------------------------------------------------------------------ +// +// initialize static data +// +int Gnuplot::tmpfile_num = 0; + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) +std::string Gnuplot::m_sGNUPlotFileName = "pgnuplot.exe"; +std::string Gnuplot::m_sGNUPlotPath = "C:/program files/gnuplot/bin/"; +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) +std::string Gnuplot::m_sGNUPlotFileName = "gnuplot"; +std::string Gnuplot::m_sGNUPlotPath = "/usr/local/bin/"; +#endif + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) +std::string Gnuplot::terminal_std = "windows"; +#elif ( defined(unix) || defined(__unix) || defined(__unix__) ) && !defined(__APPLE__) +std::string Gnuplot::terminal_std = "x11"; +#elif defined(__APPLE__) +std::string Gnuplot::terminal_std = "aqua"; +#endif + +//------------------------------------------------------------------------------ +// +// constructor: set a style during construction +// +inline Gnuplot::Gnuplot(const std::string &style) +:gnucmd(NULL) ,valid(false) ,two_dim(false) ,nplots(0) + +{ + init(); + set_style(style); +} + + +//------------------------------------------------------------------------------ +// +// constructor: open a new session, plot a signal (x) +// +inline Gnuplot::Gnuplot(const std::vector &x, + const std::string &title, + const std::string &style, + const std::string &labelx, + const std::string &labely) +:gnucmd(NULL) ,valid(false) ,two_dim(false) ,nplots(0) +{ + init(); + + set_style(style); + set_xlabel(labelx); + set_ylabel(labely); + + plot_x(x,title); +} + + +//------------------------------------------------------------------------------ +// +// constructor: open a new session, plot a signal (x,y) +// +inline Gnuplot::Gnuplot(const std::vector &x, + const std::vector &y, + const std::string &title, + const std::string &style, + const std::string &labelx, + const std::string &labely) +:gnucmd(NULL) ,valid(false) ,two_dim(false) ,nplots(0) +{ + init(); + + set_style(style); + set_xlabel(labelx); + set_ylabel(labely); + + plot_xy(x,y,title); +} + + +//------------------------------------------------------------------------------ +// +// constructor: open a new session, plot a signal (x,y,z) +// +inline Gnuplot::Gnuplot(const std::vector &x, + const std::vector &y, + const std::vector &z, + const std::string &title, + const std::string &style, + const std::string &labelx, + const std::string &labely, + const std::string &labelz) +:gnucmd(NULL) ,valid(false) ,two_dim(false) ,nplots(0) +{ + init(); + + set_style(style); + set_xlabel(labelx); + set_ylabel(labely); + set_zlabel(labelz); + + plot_xyz(x,y,z,title); +} + + +//------------------------------------------------------------------------------ +// +/// Plots a 2d graph from a list of doubles: x +// +template +Gnuplot& Gnuplot::plot_x(const X& x, const std::string &title) +{ + if (x.size() == 0) + { + throw GnuplotException("std::vector too small"); + return *this; + } + + std::ofstream tmp; + std::string name = create_tmpfile(tmp); + if (name == "") + return *this; + + // + // write the data to file + // + for (unsigned int i = 0; i < x.size(); i++) + tmp << x[i] << std::endl; + + tmp.flush(); + tmp.close(); + + plotfile_x(name, 1, title); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +/// Plots a 2d graph from a list of doubles: x y +// +template +Gnuplot& Gnuplot::plot_xy(const X& x, const Y& y, const std::string &title) +{ + if (x.size() == 0 || y.size() == 0) + { + throw GnuplotException("std::vectors too small"); + return *this; + } + + if (x.size() != y.size()) + { + throw GnuplotException("Length of the std::vectors differs"); + return *this; + } + + std::ofstream tmp; + std::string name = create_tmpfile(tmp); + if (name == "") + return *this; + + // + // write the data to file + // + for (unsigned int i = 0; i < x.size(); i++) + tmp << x[i] << " " << y[i] << std::endl; + + tmp.flush(); + tmp.close(); + + plotfile_xy(name, 1, 2, title); + + return *this; +} + + +///----------------------------------------------------------------------------- +/// +/// plot x,y pairs with dy errorbars +/// +template +Gnuplot& Gnuplot::plot_xy_err(const X &x, + const Y &y, + const E &dy, + const std::string &title) +{ + if (x.size() == 0 || y.size() == 0 || dy.size() == 0) + { + throw GnuplotException("std::vectors too small"); + return *this; + } + + if (x.size() != y.size() || y.size() != dy.size()) + { + throw GnuplotException("Length of the std::vectors differs"); + return *this; + } + + std::ofstream tmp; + std::string name = create_tmpfile(tmp); + if (name == "") + return *this; + + // + // write the data to file + // + for (unsigned int i = 0; i < x.size(); i++) + tmp << x[i] << " " << y[i] << " " << dy[i] << std::endl; + + tmp.flush(); + tmp.close(); + + // Do the actual plot + plotfile_xy_err(name, 1, 2, 3, title); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plots a 3d graph from a list of doubles: x y z +// +template +Gnuplot& Gnuplot::plot_xyz(const X &x, + const Y &y, + const Z &z, + const std::string &title) +{ + if (x.size() == 0 || y.size() == 0 || z.size() == 0) + { + throw GnuplotException("std::vectors too small"); + return *this; + } + + if (x.size() != y.size() || x.size() != z.size()) + { + throw GnuplotException("Length of the std::vectors differs"); + return *this; + } + + std::ofstream tmp; + std::string name = create_tmpfile(tmp); + if (name == "") + return *this; + + // + // write the data to file + // + for (unsigned int i = 0; i < x.size(); i++) + tmp << x[i] << " " << y[i] << " " << z[i] < +void stringtok (Container &container, + std::string const &in, + const char * const delimiters = " \t\n") +{ + const std::string::size_type len = in.length(); + std::string::size_type i = 0; + + while ( i < len ) + { + // eat leading whitespace + i = in.find_first_not_of (delimiters, i); + + if (i == std::string::npos) + return; // nothing left but white space + + // find the end of the token + std::string::size_type j = in.find_first_of (delimiters, i); + + // push token + if (j == std::string::npos) + { + container.push_back (in.substr(i)); + return; + } + else + container.push_back (in.substr(i, j-i)); + + // set up for next loop + i = j + 1; + } + + return; +} + + +//------------------------------------------------------------------------------ +// +// Destructor: needed to delete temporary files +// +Gnuplot::~Gnuplot() +{ + // remove_tmpfiles(); + + // A stream opened by popen() should be closed by pclose() +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + if (_pclose(gnucmd) == -1) +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + if (pclose(gnucmd) == -1) +#endif + throw GnuplotException("Problem closing communication to gnuplot"); +} + + +//------------------------------------------------------------------------------ +// +// Resets a gnuplot session (next plot will erase previous ones) +// +Gnuplot& Gnuplot::reset_plot() +{ + // remove_tmpfiles(); + nplots = 0; + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// resets a gnuplot session and sets all varibles to default +// +Gnuplot& Gnuplot::reset_all() +{ + // remove_tmpfiles(); + nplots = 0; + cmd("reset"); + cmd("clear"); + pstyle = "points"; + smooth = ""; + showonscreen(); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Change the plotting style of a gnuplot session +// +Gnuplot& Gnuplot::set_style(const std::string &stylestr) +{ + if (stylestr.find("lines") == std::string::npos && + stylestr.find("points") == std::string::npos && + stylestr.find("linespoints") == std::string::npos && + stylestr.find("impulses") == std::string::npos && + stylestr.find("dots") == std::string::npos && + stylestr.find("steps") == std::string::npos && + stylestr.find("fsteps") == std::string::npos && + stylestr.find("histeps") == std::string::npos && + stylestr.find("boxes") == std::string::npos && // 1-4 columns of data are required + stylestr.find("filledcurves") == std::string::npos && + stylestr.find("histograms") == std::string::npos ) //only for one data column + // stylestr.find("labels") == std::string::npos && // 3 columns of data are required + // stylestr.find("xerrorbars") == std::string::npos && // 3-4 columns of data are required + // stylestr.find("xerrorlines") == std::string::npos && // 3-4 columns of data are required + // stylestr.find("errorbars") == std::string::npos && // 3-4 columns of data are required + // stylestr.find("errorlines") == std::string::npos && // 3-4 columns of data are required + // stylestr.find("yerrorbars") == std::string::npos && // 3-4 columns of data are required + // stylestr.find("yerrorlines") == std::string::npos && // 3-4 columns of data are required + // stylestr.find("boxerrorbars") == std::string::npos && // 3-5 columns of data are required + // stylestr.find("xyerrorbars") == std::string::npos && // 4,6,7 columns of data are required + // stylestr.find("xyerrorlines") == std::string::npos && // 4,6,7 columns of data are required + // stylestr.find("boxxyerrorbars") == std::string::npos && // 4,6,7 columns of data are required + // stylestr.find("financebars") == std::string::npos && // 5 columns of data are required + // stylestr.find("candlesticks") == std::string::npos && // 5 columns of data are required + // stylestr.find("vectors") == std::string::npos && + // stylestr.find("image") == std::string::npos && + // stylestr.find("rgbimage") == std::string::npos && + // stylestr.find("pm3d") == std::string::npos ) + { + pstyle = std::string("points"); + } + else + { + pstyle = stylestr; + } + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// smooth: interpolation and approximation of data +// +Gnuplot& Gnuplot::set_smooth(const std::string &stylestr) +{ + if (stylestr.find("unique") == std::string::npos && + stylestr.find("frequency") == std::string::npos && + stylestr.find("csplines") == std::string::npos && + stylestr.find("acsplines") == std::string::npos && + stylestr.find("bezier") == std::string::npos && + stylestr.find("sbezier") == std::string::npos ) + { + smooth = ""; + } + else + { + smooth = stylestr; + } + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// sets terminal type to windows / x11 +// +Gnuplot& Gnuplot::showonscreen() +{ + cmd("set output"); + cmd("set terminal " + Gnuplot::terminal_std); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// saves a gnuplot session to a postscript file +// +Gnuplot& Gnuplot::savetops(const std::string &filename) +{ + cmd("set terminal postscript color"); + + std::ostringstream cmdstr; + cmdstr << "set output \"" << filename << ".ps\""; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Switches legend on +// +Gnuplot& Gnuplot::set_legend(const std::string &position) +{ + std::ostringstream cmdstr; + cmdstr << "set key " << position; + + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// turns on log scaling for the x axis +// +Gnuplot& Gnuplot::set_xlogscale(const double base) +{ + std::ostringstream cmdstr; + + cmdstr << "set logscale x " << base; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// turns on log scaling for the y axis +// +Gnuplot& Gnuplot::set_ylogscale(const double base) +{ + std::ostringstream cmdstr; + + cmdstr << "set logscale y " << base; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// turns on log scaling for the z axis +// +Gnuplot& Gnuplot::set_zlogscale(const double base) +{ + std::ostringstream cmdstr; + + cmdstr << "set logscale z " << base; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// scales the size of the points used in plots +// +Gnuplot& Gnuplot::set_pointsize(const double pointsize) +{ + std::ostringstream cmdstr; + cmdstr << "set pointsize " << pointsize; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// set isoline density (grid) for plotting functions as surfaces +// +Gnuplot& Gnuplot::set_samples(const int samples) +{ + std::ostringstream cmdstr; + cmdstr << "set samples " << samples; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// set isoline density (grid) for plotting functions as surfaces +// +Gnuplot& Gnuplot::set_isosamples(const int isolines) +{ + std::ostringstream cmdstr; + cmdstr << "set isosamples " << isolines; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// enables contour drawing for surfaces set contour {base | surface | both} +// +Gnuplot& Gnuplot::set_contour(const std::string &position) +{ + if (position.find("base") == std::string::npos && + position.find("surface") == std::string::npos && + position.find("both") == std::string::npos ) + { + cmd("set contour base"); + } + else + { + cmd("set contour " + position); + } + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// set labels +// +// set the xlabel +Gnuplot& Gnuplot::set_xlabel(const std::string &label) +{ + std::ostringstream cmdstr; + + cmdstr << "set xlabel \"" << label << "\""; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// set the ylabel +// +Gnuplot& Gnuplot::set_ylabel(const std::string &label) +{ + std::ostringstream cmdstr; + + cmdstr << "set ylabel \"" << label << "\""; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// set the zlabel +// +Gnuplot& Gnuplot::set_zlabel(const std::string &label) +{ + std::ostringstream cmdstr; + + cmdstr << "set zlabel \"" << label << "\""; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// set range +// +// set the xrange +Gnuplot& Gnuplot::set_xrange(const double iFrom, + const double iTo) +{ + std::ostringstream cmdstr; + + cmdstr << "set xrange[" << iFrom << ":" << iTo << "]"; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// set the yrange +// +Gnuplot& Gnuplot::set_yrange(const double iFrom, + const double iTo) +{ + std::ostringstream cmdstr; + + cmdstr << "set yrange[" << iFrom << ":" << iTo << "]"; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// set the zrange +// +Gnuplot& Gnuplot::set_zrange(const double iFrom, + const double iTo) +{ + std::ostringstream cmdstr; + + cmdstr << "set zrange[" << iFrom << ":" << iTo << "]"; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// set the palette range +// +Gnuplot& Gnuplot::set_cbrange(const double iFrom, + const double iTo) +{ + std::ostringstream cmdstr; + + cmdstr << "set cbrange[" << iFrom << ":" << iTo << "]"; + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plots a linear equation y=ax+b (where you supply the +// slope a and intercept b) +// +Gnuplot& Gnuplot::plot_slope(const double a, + const double b, + const std::string &title) +{ + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == true) + cmdstr << "replot "; + else + cmdstr << "plot "; + + cmdstr << a << " * x + " << b << " title \""; + + if (title == "") + cmdstr << "f(x) = " << a << " * x + " << b; + else + cmdstr << title; + + cmdstr << "\" with " << pstyle; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plot an equation supplied as a std::string y=f(x) (only f(x) expected) +// +Gnuplot& Gnuplot::plot_equation(const std::string &equation, + const std::string &title) +{ + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == true) + cmdstr << "replot "; + else + cmdstr << "plot "; + + cmdstr << equation << " title \""; + + if (title == "") + cmdstr << "f(x) = " << equation; + else + cmdstr << title; + + cmdstr << "\" with " << pstyle; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// plot an equation supplied as a std::string y=(x) +// +Gnuplot& Gnuplot::plot_equation3d(const std::string &equation, + const std::string &title) +{ + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == false) + cmdstr << "replot "; + else + cmdstr << "splot "; + + cmdstr << equation << " title \""; + + if (title == "") + cmdstr << "f(x,y) = " << equation; + else + cmdstr << title; + + cmdstr << "\" with " << pstyle; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plots a 2d graph from a list of doubles (x) saved in a file +// +Gnuplot& Gnuplot::plotfile_x(const std::string &filename, + const unsigned int column, + const std::string &title) +{ + // + // check if file exists + // + file_available(filename); + + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == true) + cmdstr << "replot "; + else + cmdstr << "plot "; + + cmdstr << "\"" << filename << "\" using " << column; + + if (title == "") + cmdstr << " notitle "; + else + cmdstr << " title \"" << title << "\" "; + + if(smooth == "") + cmdstr << "with " << pstyle; + else + cmdstr << "smooth " << smooth; + + // + // Do the actual plot + // + cmd(cmdstr.str()); //nplots++; two_dim = true; already in cmd(); + + return *this; +} + + + +//------------------------------------------------------------------------------ +// +// Plots a 2d graph from a list of doubles (x y) saved in a file +// +Gnuplot& Gnuplot::plotfile_xy(const std::string &filename, + const unsigned int column_x, + const unsigned int column_y, + const std::string &title) +{ + // + // check if file exists + // + file_available(filename); + + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == true) + cmdstr << "replot "; + else + cmdstr << "plot "; + + cmdstr << "\"" << filename << "\" using " << column_x << ":" << column_y; + + if (title == "") + cmdstr << " notitle "; + else + cmdstr << " title \"" << title << "\" "; + + if(smooth == "") + cmdstr << "with " << pstyle; + else + cmdstr << "smooth " << smooth; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plots a 2d graph with errorbars from a list of doubles (x y dy) in a file +// +Gnuplot& Gnuplot::plotfile_xy_err(const std::string &filename, + const unsigned int column_x, + const unsigned int column_y, + const unsigned int column_dy, + const std::string &title) +{ + // + // check if file exists + // + file_available(filename); + + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == true) + cmdstr << "replot "; + else + cmdstr << "plot "; + + cmdstr << "\"" << filename << "\" using " + << column_x << ":" << column_y << ":" << column_dy + << " with errorbars "; + + if (title == "") + cmdstr << " notitle "; + else + cmdstr << " title \"" << title << "\" "; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Plots a 3d graph from a list of doubles (x y z) saved in a file +// +Gnuplot& Gnuplot::plotfile_xyz(const std::string &filename, + const unsigned int column_x, + const unsigned int column_y, + const unsigned int column_z, + const std::string &title) +{ + // + // check if file exists + // + file_available(filename); + + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == false) + cmdstr << "replot "; + else + cmdstr << "splot "; + + cmdstr << "\"" << filename << "\" using " << column_x << ":" << column_y + << ":" << column_z; + + if (title == "") + cmdstr << " notitle with " << pstyle; + else + cmdstr << " title \"" << title << "\" with " << pstyle; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + + +//------------------------------------------------------------------------------ +// +/// * note that this function is not valid for versions of GNUPlot below 4.2 +// +Gnuplot& Gnuplot::plot_image(const unsigned char * ucPicBuf, + const unsigned int iWidth, + const unsigned int iHeight, + const std::string &title) +{ + std::ofstream tmp; + std::string name = create_tmpfile(tmp); + if (name == "") + return *this; + + // + // write the data to file + // + int iIndex = 0; + for(int iRow = 0; iRow < iHeight; iRow++) + { + for(int iColumn = 0; iColumn < iWidth; iColumn++) + { + tmp << iColumn << " " << iRow << " " + << static_cast(ucPicBuf[iIndex++]) << std::endl; + } + } + + tmp.flush(); + tmp.close(); + + std::ostringstream cmdstr; + // + // command to be sent to gnuplot + // + if (nplots > 0 && two_dim == true) + cmdstr << "replot "; + else + cmdstr << "plot "; + + if (title == "") + cmdstr << "\"" << name << "\" with image"; + else + cmdstr << "\"" << name << "\" title \"" << title << "\" with image"; + + // + // Do the actual plot + // + cmd(cmdstr.str()); + + return *this; +} + + + +//------------------------------------------------------------------------------ +// +// Sends a command to an active gnuplot session +// +Gnuplot& Gnuplot::cmd(const std::string &cmdstr) +{ + if( !(valid) ) + { + return *this; + } + + // int fputs ( const char * str, FILE * stream ); + // writes the string str to the stream. + // The function begins copying from the address specified (str) until it + // reaches the terminating null character ('\0'). This final + // null-character is not copied to the stream. + fputs( (cmdstr+"\n").c_str(), gnucmd ); + + // int fflush ( FILE * stream ); + // If the given stream was open for writing and the last i/o operation was + // an output operation, any unwritten data in the output buffer is written + // to the file. If the argument is a null pointer, all open files are + // flushed. The stream remains open after this call. + fflush(gnucmd); + + if( cmdstr.find("replot") != std::string::npos ) + { + return *this; + } + else if( cmdstr.find("splot") != std::string::npos ) + { + two_dim = false; + nplots++; + } + else if( cmdstr.find("plot") != std::string::npos ) + { + two_dim = true; + nplots++; + } + + return *this; +} + + +//------------------------------------------------------------------------------ +// +// Opens up a gnuplot session, ready to receive commands +// +void Gnuplot::init() +{ + // char * getenv ( const char * name ); get value of environment variable + // Retrieves a C string containing the value of the environment variable + // whose name is specified as argument. If the requested variable is not + // part of the environment list, the function returns a NULL pointer. +#if ( defined(unix) || defined(__unix) || defined(__unix__) ) && !defined(__APPLE__) + if (getenv("DISPLAY") == NULL) + { + valid = false; + throw GnuplotException("Can't find DISPLAY variable"); + } +#endif + + // if gnuplot not available + if (!Gnuplot::get_program_path()) + { + valid = false; + throw GnuplotException("Can't find gnuplot"); + } + + // + // open pipe + // + std::string tmp = Gnuplot::m_sGNUPlotPath + "/" + + Gnuplot::m_sGNUPlotFileName; + + // FILE *popen(const char *command, const char *mode); + // The popen() function shall execute the command specified by the string + // command, create a pipe between the calling program and the executed + // command, and return a pointer to a stream that can be used to either read + // from or write to the pipe. +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + gnucmd = _popen(tmp.c_str(),"w"); +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + gnucmd = popen(tmp.c_str(),"w"); +#endif + + // popen() shall return a pointer to an open stream that can be used to read + // or write to the pipe. Otherwise, it shall return a null pointer and may + // set errno to indicate the error. + if (!gnucmd) + { + valid = false; + throw GnuplotException("Couldn't open connection to gnuplot"); + } + + nplots = 0; + valid = true; + smooth = ""; + + //set terminal type + showonscreen(); + + return; +} + + +//------------------------------------------------------------------------------ +// +// Find out if a command lives in m_sGNUPlotPath or in PATH +// +bool Gnuplot::get_program_path() +{ + // + // first look in m_sGNUPlotPath for Gnuplot + // + std::string tmp = Gnuplot::m_sGNUPlotPath + "/" + + Gnuplot::m_sGNUPlotFileName; + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + if ( Gnuplot::file_exists(tmp,0) ) // check existence +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + if ( Gnuplot::file_exists(tmp,1) ) // check existence and execution permission +#endif + { + return true; + } + + // + // second look in PATH for Gnuplot + // + char *path; + // Retrieves a C string containing the value of environment variable PATH + path = getenv("PATH"); + + if (path == NULL) + { + throw GnuplotException("Path is not set"); + return false; + } + else + { + std::list ls; + + //split path (one long string) into list ls of strings +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + stringtok(ls,path,";"); +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + stringtok(ls,path,":"); +#endif + + // scan list for Gnuplot program files + for (std::list::const_iterator i = ls.begin(); + i != ls.end(); ++i) + { + tmp = (*i) + "/" + Gnuplot::m_sGNUPlotFileName; +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + if ( Gnuplot::file_exists(tmp,0) ) // check existence +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + if ( Gnuplot::file_exists(tmp,1) ) // check existence and execution permission +#endif + { + Gnuplot::m_sGNUPlotPath = *i; // set m_sGNUPlotPath + return true; + } + } + + tmp = "Can't find gnuplot neither in PATH nor in \"" + + Gnuplot::m_sGNUPlotPath + "\""; + throw GnuplotException(tmp); + + Gnuplot::m_sGNUPlotPath = ""; + return false; + } +} + + + +//------------------------------------------------------------------------------ +// +// check if file exists +// +bool Gnuplot::file_exists(const std::string &filename, int mode) +{ + if ( mode < 0 || mode > 7) + { + throw std::runtime_error("In function \"Gnuplot::file_exists\": mode\ + has to be an integer between 0 and 7"); + return false; + } + + // int _access(const char *path, int mode); + // returns 0 if the file has the given mode, + // it returns -1 if the named file does not exist or is not accessible in + // the given mode + // mode = 0 (F_OK) (default): checks file for existence only + // mode = 1 (X_OK): execution permission + // mode = 2 (W_OK): write permission + // mode = 4 (R_OK): read permission + // mode = 6 : read and write permission + // mode = 7 : read, write and execution permission +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + if (_access(filename.c_str(), mode) == 0) +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + if (access(filename.c_str(), mode) == 0) +#endif + { + return true; + } + else + { + return false; + } +} + + +bool Gnuplot::file_available(const std::string &filename) +{ + std::ostringstream except; + if( Gnuplot::file_exists(filename,0) ) // check existence + { + if( !(Gnuplot::file_exists(filename,4)) ){// check read permission + except << "No read permission for File \"" << filename << "\""; + throw GnuplotException( except.str() ); + return false; + } + } + else + { + except << "File \"" << filename << "\" does not exist"; + throw GnuplotException( except.str() ); + return false; + } + return true; +} + + + +//------------------------------------------------------------------------------ +// +// Opens a temporary file +// +std::string Gnuplot::create_tmpfile(std::ofstream &tmp) +{ +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + char name[] = "gnuplotiXXXXXX"; //tmp file in working directory +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + char name[] = "/tmp/gnuplotiXXXXXX"; // tmp file in /tmp +#endif + + // + // check if maximum number of temporary files reached + // + if (Gnuplot::tmpfile_num == GP_MAX_TMP_FILES - 1) + { + std::ostringstream except; + except << "Maximum number of temporary files reached (" + << GP_MAX_TMP_FILES << "): cannot open more files" << std::endl; + + throw GnuplotException( except.str() ); + return ""; + } + + // int mkstemp(char *name); + // shall replace the contents of the string pointed to by "name" by a unique + // filename, and return a file descriptor for the file open for reading and + // writing. Otherwise, -1 shall be returned if no suitable file could be + // created. The string in template should look like a filename with six + // trailing 'X' s; mkstemp() replaces each 'X' with a character from the + // portable filename character set. The characters are chosen such that the + // resulting name does not duplicate the name of an existing file at the + // time of a call to mkstemp() + + // + // open temporary files for output + // +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + if (_mktemp(name) == NULL) +#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__) + if (mkstemp(name) == -1) +#endif + { + std::ostringstream except; + except << "Cannot create temporary file \"" << name << "\""; + throw GnuplotException(except.str()); + return ""; + } + + tmp.open(name); + if (tmp.bad()) + { + std::ostringstream except; + except << "Cannot create temporary file \"" << name << "\""; + throw GnuplotException(except.str()); + return ""; + } + + // + // Save the temporary filename + // + tmpfile_list.push_back(name); + Gnuplot::tmpfile_num++; + + return name; +} + + +void Gnuplot::remove_tmpfiles() +{ + if ((tmpfile_list).size() > 0) + { + for (unsigned int i = 0; i < tmpfile_list.size(); i++) + remove( tmpfile_list[i].c_str() ); + + Gnuplot::tmpfile_num -= tmpfile_list.size(); + } +} + + +#endif diff --git a/src/tests/unit-tests/arithmetic/fft_length_test.cc b/src/tests/unit-tests/arithmetic/fft_length_test.cc index 9fc0b5a8d..4b9d64826 100644 --- a/src/tests/unit-tests/arithmetic/fft_length_test.cc +++ b/src/tests/unit-tests/arithmetic/fft_length_test.cc @@ -33,14 +33,26 @@ #include #include #include +#include #include +#if defined GNUPLOT_EXECUTABLE + #include "gnuplot_i.h" + const bool exists_gnuplot_fft_test_length = true; +#elif !defined GNUPLOT_EXECUTABLE + const bool exists_gnuplot_fft_test_length = false; +#endif + + DEFINE_int32(fft_iterations_test, 1000, "Number of averaged iterations in FFT length timing test"); +DEFINE_bool(plot_fft_length_test, false, "Plots results of FFTLengthTest"); TEST(FFTLengthTest, MeasureExecutionTime) { - unsigned int fft_sizes [] = { 1000, 1024, 1960, 2000, 2048, 4000, 4096, 4725, 5000, 8000, 8192, 10368, 12000, 16000, 16384, 27000, 32768, 50000, 65536 }; + unsigned int fft_sizes [] = { 512, 1000, 1024, 1100, 1297, 1400, 1500, 1960, 2000, 2048, 2221, 2500, 3000, 3500, 4000, + 4096, 4200, 4500, 4725, 5000, 5500, 6000, 6500, 7000, 7500, 8000, 8192, 8500, 9000, 9500, 10000, 10368, 11000, + 12000, 15000, 16000, 16384, 27000, 32768, 50000, 65536 }; std::chrono::time_point start, end; @@ -54,8 +66,12 @@ TEST(FFTLengthTest, MeasureExecutionTime) auto gen = std::bind(func, random_number1, random_number2); // Function that returns a random gr_complex std::vector fft_sizes_v(fft_sizes, fft_sizes + sizeof(fft_sizes) / sizeof(unsigned int) ); + std::sort(fft_sizes_v.begin(), fft_sizes_v.end()); std::vector::const_iterator it; unsigned int d_fft_size; + std::vector execution_times; + std::vector powers_of_two; + std::vector execution_times_powers_of_two; EXPECT_NO_THROW( for(it = fft_sizes_v.cbegin(); it != fft_sizes_v.cend(); ++it) @@ -73,9 +89,57 @@ TEST(FFTLengthTest, MeasureExecutionTime) } end = std::chrono::system_clock::now(); std::chrono::duration elapsed_seconds = end - start; - double execution_time = elapsed_seconds.count() / static_cast(FLAGS_fft_iterations_test); - std::cout << "FFT execution time for length=" << d_fft_size << " : " << execution_time << " [s]" << std::endl; + double exec_time = elapsed_seconds.count() / static_cast(FLAGS_fft_iterations_test); + execution_times.push_back(exec_time * 1e3); + std::cout << "FFT execution time for length=" << d_fft_size << " : " << exec_time << " [s]" << std::endl; delete d_fft; + + if( (d_fft_size & (d_fft_size - 1)) == 0 ) // if it is a power of two + { + powers_of_two.push_back(d_fft_size); + execution_times_powers_of_two.push_back(exec_time / 1e-3); + } + } ); + + if(FLAGS_plot_fft_length_test == true) + { + if(!exists_gnuplot_fft_test_length) + { + std::cout << "WARNING: Although the flag plot_fft_length_test has been set to TRUE," << std::endl; + std::cout << "gnuplot has not been found in your system." << std::endl; + std::cout << "Test results will not be plotted." << std::endl; + } + else + { +#if defined GNUPLOT_EXECUTABLE + std::string gnuplot_executable = std::string(GNUPLOT_EXECUTABLE); + boost::filesystem::path p(gnuplot_executable); + boost::filesystem::path dir = p.parent_path(); + std::string gnuplot_path = dir.native(); + Gnuplot::set_GNUPlotPath(gnuplot_path); + + Gnuplot g1("linespoints"); + g1.set_title("FFT execution times for different lengths"); + g1.set_grid(); + g1.set_xlabel("FFT length"); + g1.set_ylabel("Execution time [ms]"); + g1.plot_xy(fft_sizes_v, execution_times, "FFT execution time (averaged over " + std::to_string(FLAGS_fft_iterations_test) + " iterations)"); + g1.set_style("points").plot_xy(powers_of_two, execution_times_powers_of_two, "Power of 2"); + g1.showonscreen(); // window output + + Gnuplot g2("linespoints"); + g2.set_title("FFT execution times for different lengths (up to 2^{14}=16384)"); + g2.set_grid(); + g2.set_xlabel("FFT length"); + g2.set_ylabel("Execution time [ms]"); + g2.set_xrange(0, 16384); + g2.plot_xy(fft_sizes_v, execution_times, "FFT execution time (averaged over " + std::to_string(FLAGS_fft_iterations_test) + " iterations)"); + g2.set_style("points").plot_xy(powers_of_two, execution_times_powers_of_two, "Power of 2"); + g2.savetops("FFT_execution_times"); + g2.showonscreen(); // window output +#endif + } + } }