[SOLVED] Very basic question: How to handle multiple output ASCII files?


I just got started with Palabos and with C++ in general. Prior to this, I only had experience with C, so the jump from a structured programming language to a fully object-oriented one is quite large. I believe my difficulty resides more on the side of programming than Palabos itself, but I think this community is the best place to find the answers I need.

Before I started trying to fiddle with the examples to solve some problems I want to solve, I studied the Tutorial available on the wiki. But what I want to do is not covered on any example.

I started toying with /examples/showCaes/poiseuille/poiseuille.cpp, because this will be the skeleton to the problem I want to model. The code as-is saves only images snapshots with the velocity norm, but I want to write ASCII files as well with the y coordinate of the duct on the first column and the velocity norm on the second column. By following the example useIOstream.cpp, I found that I had to create a Box2D object to extract these informations from the slice I want, so I replicated this on my code. This works, but I have two problems. I’ll first pose the problems and then detail what I tried to do:

  1. I want my output files to be called something like “profiles_t???.dat”, where ??? is the time step. I want these ASCII files to follow the naming convention of the .gif image files, which are named “u???.gif”;
  2. I’m not that familiar with C++ I/O, so how do I write the output file in the way I want? On C (pseudocode) this would be something like fprintf(output, “%f %f\n”, y, velocityNorm);

For #1, I tried many things, among them writing a string and parsing this string to the object plb_ofstream as

ostringstream oss;
oss << “profiles_t” << iT*parameters.getDeltaT() << “.dat”;
fileName = oss.str();
//pcout << filename << endl; Debug

        plb_ofstream successiveProfiles(filename);

The commented pcout is just to check on the terminal if the string was being built on the way I wanted (it was). This method does not work, and the compiler throws a lot of errors. The second thing I tried was to parse the data directly to plb_ofstream as

plb_ofstream(successiveProfiles("profiles_t" << iT*parameters.getDeltaT() << ".dat");

but this also does not work, and the compilation terminates with an error

poiseuille.cpp: In function ‘int main(int, char**)’:
poiseuille.cpp:264:78: error: invalid operands of types ‘const char [11]’ and ‘double’ to binary ‘operator<<’
      plb_ofstream successiveProfiles("profiles_t" << iT*parameters.getDeltaT() << ".dat");
scons: *** [poiseuille.o] Error 1

So, how do I do this? I apologize in advance for taking your time for such basic question, and thank you in advance for your time.


Well, it certainly was my lack of C++. I found a (somewhat dirty) way of doing both things I need, so even though this was a very low-level question I’ll relate my solution because other newbies like me may need this.

#1 - Saving several ASCII files

I created a stringstream and a string variables called buffer and filename, respectively. With “buffer” I build the filename I want, and then I parse this to the filename variable. Then, I use plb_ofstream to open a file whose name is stored on the “filename” variable and clear the buffer for the next time iteration:

stringstream buffer;
string filename;


buffer << "profiles_t";
buffer << iT*parameters.getDeltaT();
buffer << ".dat";
filename = buffer.str();
pcout << filename << endl;    // Just prints the contents of filename to the terminal to check if everything's allright

plb_ofstream successiveProfiles(filename.c_str());

With this, I can write the filenames as I wanted, for example, "profiles_t0.5.dat", "profiles_t1.2.dat", etc.

#2 - Writing the ASCII files with two columns, with the y position on the first and the velocity norm on the second

This was trickier, and I'm certain there's a more elegant way to do this, but what I did works. Since this is a computationally fast problem and I'm still learning, I think it's not a big hassle.  I noted that by defining a Box2D with the vertical slice of interest to extract the velocities, the code useIOstream.cpp used

Box2D profileSection(nx/2, nx/2, 0, ny-1);
                << setprecision(4)
                  // (2) Convert from lattice to physical units.
                << *multiply (
                       parameters.getDeltaX() / parameters.getDeltaT(),
                  // (1) Compute velocity norm along the chosen section.
                       *computeVelocityNorm (lattice, profileSection) )
                << endl;

but produced the output file in a single line. This is ok for people who use Matlab or Octave, but I’m more comfortable with Gnuplot, and data files like those are a bit trickier to work with. So I defined a loop over the vertical direction, from ny = 0 to ny = the maximum ny and defined a Box2D at each ny point:

for(ny = 0; ny <= parameters.getNy() - 1; ny ++)
Box2D profileSection(nx/2, nx/2, ny, ny);
successiveProfiles << setprecision(5) << ny << " " << *multiply ( parameters.getDeltaX() / parameters.getDeltaT(), *computeVelocityNorm (lattice, profileSection) ) << endl;

With this, my output files look the way I wanted, and are formatted in a way that Gnuplot can handle directly. 

This is, obviously, not the best solution, but if possible I would like to know what's the best, most elegant way of doing this.

Thank you for your time!