Skip to content

Instantly share code, notes, and snippets.

@jwpeterson
Created April 7, 2021 21:13
Show Gist options
  • Save jwpeterson/6b812271ee7dc31a24b1a60b8fe3edde to your computer and use it in GitHub Desktop.
Save jwpeterson/6b812271ee7dc31a24b1a60b8fe3edde to your computer and use it in GitHub Desktop.
Convert the output of PetscMatrix::print_matlab() to a format which can be used in Python
// C++ header files
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <cstdlib> // std::exit
#include <getopt.h> // getopt_long()
void usage(const char * progname)
{
std::cerr << "Usage: " << progname << " -i <filename>" << std::endl;
}
int main(int argc, char** argv)
{
// options descriptor - this associates "long" and "short" command line options.
static struct option longopts[] =
{
{"input-file", required_argument, NULL, 'i'},
{"help", no_argument, NULL, 'h'},
{ NULL, 0, NULL, 0 }
};
std::string infile_name;
// Parse command line options using getopt_long()
int ch = -1;
while ((ch = getopt_long(argc, argv, "hi:", longopts, NULL)) != -1)
{
switch (ch)
{
case 'i':
{
infile_name = optarg;
break;
}
case 'h':
{
usage(argv[0]);
std::exit(1);
}
default:
// We could error here, print a usage command, or just ignore unrecognized arguments...
std::cerr << "Unrecognized argument: " << optarg << std::endl;
usage(argv[0]);
}
} // end while
// Check for valid input filename
if (infile_name.empty())
{
usage(argv[0]);
std::exit(1);
}
// Open example file for reading
std::ifstream infile(infile_name);
// File we will write the results to. By default it is the same
// basename as the input file but with a .py extension.
std::string outfile_name = infile_name;
outfile_name.erase(outfile_name.find_last_of("."));
outfile_name += ".py";
// Don't try to overwrite the input
if (outfile_name == infile_name)
{
std::cerr << "Error: input and output filenames cannot match." << std::endl;
std::exit(1);
}
std::ofstream outfile(outfile_name);
outfile << std::scientific << std::setprecision(16);
// The number of rows and cols in the input matrix
unsigned int nrows = 0;
unsigned int ncols = 0;
// Parse file line by line
std::string line;
// Used for formatted parsing of a single line
std::stringstream line_stream;
// Used for reading strings line by line
std::string dummy;
unsigned int row = 0;
unsigned int col = 0;
double val = 0.;
// Write "header" to Python file
outfile << "import matplotlib.pyplot as plt" << std::endl;
outfile << "from scipy.sparse import coo_matrix" << std::endl;
outfile << "array = [" << std::endl;
while (true)
{
// Try to read something. This may set EOF!
std::getline(infile, line);
if (infile)
{
// Debugging: print line to file
// std::cout << line << std::endl;
// 1.) Process line which tells the matrix size and looks like this
// % Size = 30 30
if (line.find("Size") != std::string::npos)
{
// Create a stream object out of the current line
line_stream.clear();
line_stream.str(line);
line_stream >> dummy >> dummy >> dummy >> nrows >> ncols;
}
// 2.) Process a line that starts with a number. It should have three entries
if (line.find_first_of("0123456789") == 0)
{
line_stream.clear();
line_stream.str(line);
line_stream >> row >> col >> val;
// Check that it worked
if (row == 0 || col == 0)
{
std::cerr << "Error reading row and/or column indices" << std::endl;
std::exit(1);
}
// Write zero-based (!) indices to output file separated by commas
outfile << row-1 << "," << col-1 << "," << val << "," << std::endl;
}
// Go to next line
continue;
}
if (infile.eof())
break;
// If we made it here, there was an error
std::cerr << "Error while parsing file (be sure file exists)." << std::endl;
std::exit(1);
}
// Close array
outfile << "]" << std::endl;
// Check that we read a valid number of rows and columns
if (nrows == 0 || ncols == 0)
{
std::cerr << "Error reading number of rows and cols in matrix" << std::endl;
std::exit(1);
}
// Write "footer" to Python file
outfile << "rows = array[0::3]" << std::endl;
outfile << "cols = array[1::3]" << std::endl;
outfile << "data = array[2::3]" << std::endl;
outfile << "mat = coo_matrix((data, (rows, cols)), shape=(" << nrows << "," << ncols << "))" << std::endl;
outfile << "fig = plt.figure()" << std::endl;
outfile << "ax1 = fig.add_subplot(111)" << std::endl;
outfile << "ax1.spy(mat, markersize=1)" << std::endl; // non-zero values with |Z|>precision will be plotted, default is precision=0.0
outfile << "plt.savefig('spy_nonzero.pdf', format='pdf')" << std::endl;
outfile << "ax1.spy(mat, precision='present', markersize=1)" << std::endl; // plot all "present" values (even zeros)
outfile << "plt.savefig('spy_present.pdf', format='pdf')" << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment