Tuesday, September 1, 2009

Using POOMA With Excel, OpenGL, and HippoDraw


In a prior post I covered the basics of how you can extract data from POOMA for display in your programs. I'm going to expand on that now and show how you can use POOMA with Excel or Numbers, OpenGL, and HippoDraw. The code discussed in this post can be downloaded from SourceForge at the following locations:

Download POOMAIO.h
Download POOMAIOTest.cpp

POOMAIO.h contains classes for writing POOMA Array values to CSV files, to TNT files, and to a format usable as translate values in OpenGL programs. POOMAIOTest.cpp is the electron bounce program from the previous post re-written to use these new IO capabilities.

To use these new classes, you instantiate them and call their write() method with the appropriate parameters.

Using POOMA Data In Excel Or Numbers
Both Excel and Numbers are spreadsheets that can read CSV (Comma Separated Values) files. POOMIO.h contains a class named VectorCSVOutput that will write POOMA array values in CSV format. VectorCSVOutput is a template that takes the number of dimensions of the POOMA array and the data type of values stored in that array. Once you've instantiated the class, call it's write method passing in the output stream, POOMA array to write, and character delimiter to use. The character delimiter defaults to a comma, and you'll probably want to stick with that. An example that prints the positions of electrons is shown below along with a screen shot of the resulting values as they appear in Numbers.


VectorCSVOutput<3> oVectorCSVOutput;

for (unsigned int iLoop5 = 0; iLoop5 < iNumberOfParticles; iLoop5++)
{
CustomParticle<PTraits_t>::PointType_t oThisElectronPosition = oElectron.pos(iLoop5);

cout << iLoop5 << ","; // Print out the number of each particle.
oVectorCSVOutput.write(cout, oThisElectronPosition);
cout << endl;
} // for



Using POOMA Data In HippoDraw
The next output format we're going to look at is the TNT format. The TNT format can be read by HippoDraw, which is a data analysis tool from SLAC. The class used to write POOMA arrays to the TNT format is VectorTNTOutput, which inherits from VectorCSVOutput. The only additional work you need to do for VectorCSVOutput is to call its writeHeaders() method. The write headers method takes an output stream, a title and a vector of column labels as parameters. An example of using this class is shown below.

VectorTNTOutput<3> oVectorTNTOutput;
vector<string> vLabels;

vLabels.push_back(string("Particle"));
vLabels.push_back(string("X"));
vLabels.push_back(string("Y"));
vLabels.push_back(string("Z"));

oVectorTNTOutput.writeHeaders(cout, string("Electron Bounce"), vLabels);

// .... perform work ....

for (unsigned int iLoop5 = 0; iLoop5 < iNumberOfParticles; iLoop5++)
{
CustomParticle<PTraits_t>::PointType_t oThisElectronPosition = oElectron.pos(iLoop5);

cout << iLoop5 << ",";
oVectorTNTOutput.write(cout, oThisElectronPosition);
cout << endl;
} // for



Using POOMA Data In OpenGL
OpenGL usually only need translations from POOMA. You'll create the objects you want to display as meshes and translate them to their correct location based on data provided by POOMA. However, OpenGL programs often want their position values normalized between a value of -1 and 1 in the X and Y directions and a value of 0.1 and some maximum value in the Z direction. There are two classes to help you with this translation, VectorOpenGLOutput, which writes scaled translation values to standard out as a C array of floats, and VectorOpenGLVectorOutput, which stores scaled translation values in a C++ vector. Both of these classes need to be told what the maximum value will be in your POOMA array and how you want to offset the X, Y, and Z values. The maximum values are used to scale down the values in the array to make them usable by OpenGL. The offset then moves the X, Y, and Z positions so they appear on the screen.

With VectorOpenGLOutput you can write values to standard out, and then cut and paste them directly into C or C++ code for later replay. The example below shows the code to do this.

CustomParticle<PTraits_t>::PointType_t oMaxValues;
CustomParticle<PTraits_t>::PointType_t oOffsets;
VectorOpenGLOutput<3> oVectorOpenGLOutput;

oMaxValues(0) = 99;
oMaxValues(1) = 99;
oMaxValues(2) = 99;
oOffsets(0) = 1;
oOffsets(1) = 1;
oOffsets(2) = -0.1;
cout << "float aTranslate" << iLoop2 << "[" << iNumberOfParticles << "][3]{" << endl;
for (unsigned int iLoop5 = 0; iLoop5 < iNumberOfParticles; iLoop5++)
{
CustomParticle<PTraits_t>::PointType_t oThisElectronPosition = oElectron.pos(iLoop5);

oVectorOpenGLOutput.write(cout, oThisElectronPosition, oMaxValues, oOffsets);
} // for
cout << "};" << endl;


The VectorOpenGLVectorOutput stores the scaled values in an array so you can use them right away in your program. An example is shown below.

CustomParticle<PTraits_t>::PointType_t oMaxValues;
CustomParticle<PTraits_t>::PointType_t oOffsets;
VectorOpenGLVectorOutput<3> oVectorOpenGLVectorOutput;
vector<CustomParticle<PTraits_t>::AxisType_t> vPositions;

oMaxValues(0) = 99;
oMaxValues(1) = 99;
oMaxValues(2) = 99;
oOffsets(0) = 1;
oOffsets(1) = 1;
oOffsets(2) = -0.1;
for (unsigned int iLoop5 = 0; iLoop5 < iNumberOfParticles; iLoop5++)
{
CustomParticle<PTraits_t>::PointType_t oThisElectronPosition = oElectron.pos(iLoop5);

oVectorOpenGLVectorOutput.write(vPositions, oThisElectronPosition, oMaxValues, oOffsets);
// ... Call OpenGL as needed with the values stored in vPositions.
vPositions.clear();
} // for


The OpenGL examples assume a bounding box of 0 through 99 in the POOMA program for the X, Y and Z axis. This means particles cannot travel beyond those dimensions, they'll bounce of the invisible walls instead. This is the condition that was set up in the example program.

The end result of the translation to OpenGL values is the X and Y axis will be scaled to values between -1 and 1, and the Z axis will be scaled to values between 0.1 and 2.1. These scaled values are commonly used by OpenGL programs. Your OpenGL program will use gltranslatef() to translate your 3D representation of the particles using the values provided by VectorOpenGLOutput or VectorOpenGLVectorOutput.

No comments:

Post a Comment