How can I import .csv file data into gsl_vectors in C++?

Viewed 202

I have a .csv file that looks like:

X,Y,Z
0,0,0
0,0,0
-0.00624347,-0.0182673,1.00063
-0.00845628,-0.0374925,1.00058
-0.00494793,-0.0295639,0.927447
-0.00285682,-0.0926582,0.885783
-0.00832563,-0.02957,0.697834

And I want to put it into three gsl_vectors (from GSL: https://www.gnu.org/software/gsl/doc/html/vectors.html) corresponding to the column X, column Y and column Z respectively. The reason why I want to do this is because I later want to use the functions that are implemented in the GNU Scientific Library on this data. I want to emphasize that these functions can only work on gsl_vectors and not on std:vectors.

My approaches:

  1. Put the data from the .csv into std:vectors, and then transform those vectors into gsl_vectors. That did not work.

  2. Put the data from the .csv file into gsl_vectors directly:

    #include <iostream>
    #include <fstream>
    #include <istream>
    #include <string>
    #include <sstream>
    #include <algorithm>
    #include <gsl/gsl_linalg.h>
    #include <gsl/gsl_vector.h>
    
    struct acceleration {
        gsl_vector AccX;
        gsl_vector AccY;
        gsl_vector AccZ;
    };
    
    // Function prototypes
    acceleration read_csv(acceleration& A);
    // End function prototypes
    
    int main(void)
    {
        // ==================READ THE CSV=========================
        acceleration data;
        data = read_csv(data);
        printf("/n");
        gsl_vector_fprintf(stdout, &data.AccX, "%lf");
    
        return 0;
    }
    
    acceleration read_csv(acceleration& SA)
    {
        std::string buffer; /* Declare a buffer for the data that will be read */
        std::string bacx, bacy, bacz;
        std::ifstream inputfile;
        inputfile.open("buffer.csv"); /* Open file for reading */
        if (!inputfile.is_open())
        {
            std::cout << "Error opening file" << std::endl;
        }
    
        std::stringstream aux(buffer);
        getline(aux, bacx, ',');
        getline(aux, bacy, ',');
        getline(aux, bacz, ',');
        size_t i{ 0 };
    
        while (getline(inputfile, buffer))
        {
            std::stringstream aux(buffer);
    
            getline(aux, bacx, ',');
            if (bacx.compare("AX") != 0)
                gsl_vector_set(&SA.AccX, i, stod(bacx));
    
            getline(aux, bacy, ',');
            if (bacy.compare("AY") != 0)
                gsl_vector_set(&SA.AccY, i, stod(bacy));
    
            getline(aux, bacz, ',');
            if (bacz.compare("AZ") != 0)
                gsl_vector_set(&SA.AccZ, i, stod(bacz));
            i++;
        }
        inputfile.close();
        return (SA);
    
    }
    

    This gives no output on the Console and if I debug it, the function gsl_vector_set throws an exception:

    Exception thrown at 0x7A5EED1A (gsld.dll) in progr.exe: 0xC0000005: Access violation writing location 0x3333332

    At gsl_set_vector's line: v->data[i * v->stride] = x;

  3. Put the .csv data into a gsl_block and then slice it into gsl_vectors. Here I get an exception when trying to put the data into the block. Then, for slicing the block into vectors, I assume I'll have to use the gsl_vector_alloc_from_block() function, yet I did not find any example on how to use this function. I do need to see how others use functions generally because I'm new to C++. Here is what I have until now for this idea:

    #include <iostream>
    #include <fstream>
    #include <gsl/gsl_linalg.h>
    #include <gsl/gsl_vector.h>
    
    // Function prototypes
    gsl_block read_csv(void);
    // End function prototypes
    
    int main(void)
    {
        // ================== READ THE CSV INTO A BLOCK =========================
        gsl_block data;
        data = read_csv();
        // ================= NOW SLICE THE BLOCK: HOW? ==========================
        // Use gsl_vector_alloc_from_block(), but how?
        return 0;
    }
    
    // Function declarations
    gsl_block read_csv(void)
    {
        FILE* inputfile;
        fopen_s(&inputfile, "buffer.csv", "r"); /* Open file for reading */
        if (inputfile == NULL)
            std::cout << "file does not exist \n";
        fseek(inputfile, 0L, SEEK_END); // Go until the end
        int file_size = ftell(inputfile); // In order to tell the size of the file
        gsl_block* b = gsl_block_alloc(file_size);
        if(inputfile)
            gsl_block_fscanf(inputfile, b);
    
        fclose(inputfile);
    
        return *b;
    
    }
    // End function declarations
    

    If I run this I get:

    Debug Error! abort() has been called

    And on the Console it is shown:

    gsl: C:\DEV\vcpkg\buildtrees\gsl\src\gsl-2-fb511965d5.clean\block\fprintf_source.c:90: ERROR: fscanf failed Default GSL error handler invoked.

    If I debug this, the gsl_error function throws an exception:

    progr.exe has triggered a breakpoint.

    At abort ();

To sum up, I actually want to read the .csv file into gsl_vectors. If my approaches are not OK, it is understandable.

1 Answers

You can read the CSV file into gsl vectors the following way:

#include <stdio.h>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <gsl/gsl_vector.h>

int main ()
{
  int i = 0, rows = 7;

  // Allocate vectors
  gsl_vector *X = gsl_vector_alloc (rows);
  gsl_vector *Y = gsl_vector_alloc (rows);
  gsl_vector *Z = gsl_vector_alloc (rows);

  // Open the file
  std::ifstream openfile("data.csv");
  openfile.ignore(10000, '\n'); // Ignore the header
  std::string line;

  while (getline(openfile, line, '\n'))
  {
    std::string a, b, c;
    std::stringstream iss(line);
    getline(getline(getline (iss, a, ','), b, ','), c, ',');
    // std::cout << a << ' ' << b << ' ' << c << std::endl;

    // Set vectors
    gsl_vector_set (X, i, std::stod(a));
    gsl_vector_set (Y, i, std::stod(b));
    gsl_vector_set (Z, i, std::stod(c));

    i += 1;
  }

  // Close the file
  openfile.close();

  for(i = 0; i < rows; ++i)
  {
      // Get vectors
      std::cout << gsl_vector_get (X, i) << "\t";
      std::cout << gsl_vector_get (Y, i) << "\t";
      std::cout << gsl_vector_get (Z, i) << "\n";
  }

  // Do some processing with the vectors

  // Free allocated memory at the end
  gsl_vector_free (X);
  gsl_vector_free (Y);
  gsl_vector_free (Z);

  return 0;
}

Firstly, I open the data.csv using ifstream and read each line into three variables (splitting them through a comma). Secondly, I cast them into double and store them in the gsl vectors. Lastly, I print them for verification.

Related