Dear all,
when trying to write programs with palabos v1.1r0 that contain more than one .cpp file, I frequently ran into errors like
[code=“cpp”]
multiple definition of `bool plb::equals(double, double)’
To fix this, I changed the file imageWriter.hh from
[code="cpp"]
template<> bool equals(float a, float b) {
return std::fabs(a-b)<1.e-12;
}
template<> bool equals(double a, double b) {
return std::fabs(a-b)<1.e-12;
}
to
[code=“cpp”]
template<> inline bool equals(float a, float b) {
return std::fabs(a-b)<1.e-12;
}
template<> inline bool equals(double a, double b) {
return std::fabs(a-b)<1.e-12;
}
A similar error arises with
[code="cpp"]
plb::colors
in svgWriter.h - here, the solution is to move all definitions to a .cpp file. My versions that work are found here:
svgWriter.h:
[code=“cpp”]
#ifndef SVG_WRITER_2D_H
#define SVG_WRITER_2D_H
#include “multiGrid/multiGridManagement2D.h”
#include “core/util.h”
#include “io/parallelIO.h”
#include
namespace plb {
extern int colors[128][3];
template class MultiScalarField2D;
class SVGWriter2D {
public:
SVGWriter2D(MultiGridManagement2D management_);
void writePatterns();
void writeDomainsWithDynamicsInfo(std::string fileName, int dynamicsNumber,
std::vector<MultiScalarField2D > dynamicsInfo,
std::vector<std::map<int, std::string> >& idToName,
std::mapstd::string,int& nameToColor);
void writeBG(Box2D block, double size);
private:
void writeHeader();
void writeCircle(Array<double,2> location, double radius, int color);
void writeEnd();
MultiGridManagement2D management;
plb_ofstream out;
};
} // namespace plb
#endif // SVG_WRITER_2D_H
svgWriter.cpp:
[code="cpp"]
#include "svgWriter.h"
#include "multiGrid/multiGridManagement2D.h"
#include "core/util.h"
#include "multiBlock/multiDataField2D.h"
#include <string>
namespace plb {
int colors[128][3] = {
{ 255, 69, 0 }, { 30, 144, 255 }, { 0, 0, 255 }, { 255, 255, 0 }, { 0, 255, 255 }, {
255, 0, 255 }, { 192, 192, 192 }, { 0, 0, 0},
{ 200, 0, 0 }, { 0, 200, 0 }, { 0, 0, 200 }, { 200, 200, 0 }, { 0, 200, 200 }, { 200,
0, 200 }, { 100, 100, 100 }, { 200, 200, 200},
{ 100, 0, 0 }, { 0, 100, 0 }, { 0, 0, 100 }, { 100, 100, 0 }, { 0, 100, 100 }, { 100,
0, 100 }, { 50, 50, 50 }, { 100, 100, 100},
{ 50, 0, 0 }, { 0, 50, 0 }, { 0, 0, 50 }, { 50, 50, 0 }, { 0, 50, 50 }, { 50,
0, 50 }, { 25, 25, 25 }, { 50, 50, 50},
{ 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 }, { 255, 255, 0 }, { 0, 255, 255 }, { 255,
0, 255 }, { 192, 192, 192 }, { 0, 0, 0},
{ 200, 0, 0 }, { 0, 200, 0 }, { 0, 0, 200 }, { 200, 200, 0 }, { 0, 200, 200 }, { 200,
0, 200 }, { 100, 100, 100 }, { 200, 200, 200},
{ 100, 0, 0 }, { 0, 100, 0 }, { 0, 0, 100 }, { 100, 100, 0 }, { 0, 100, 100 }, { 100,
0, 100 }, { 50, 50, 50 }, { 100, 100, 100},
{ 50, 0, 0 }, { 0, 50, 0 }, { 0, 0, 50 }, { 50, 50, 0 }, { 0, 50, 50 }, { 50,
0, 50 }, { 25, 25, 25 }, { 50, 50, 50},
{ 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 }, { 255, 255, 0 }, { 0, 255, 255 }, { 255,
0, 255 }, { 192, 192, 192 }, { 0, 0, 0},
{ 200, 0, 0 }, { 0, 200, 0 }, { 0, 0, 200 }, { 200, 200, 0 }, { 0, 200, 200 }, { 200,
0, 200 }, { 100, 100, 100 }, { 200, 200, 200},
{ 100, 0, 0 }, { 0, 100, 0 }, { 0, 0, 100 }, { 100, 100, 0 }, { 0, 100, 100 }, { 100,
0, 100 }, { 50, 50, 50 }, { 100, 100, 100},
{ 50, 0, 0 }, { 0, 50, 0 }, { 0, 0, 50 }, { 50, 50, 0 }, { 0, 50, 50 }, { 50,
0, 50 }, { 25, 25, 25 }, { 50, 50, 50},
{ 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 }, { 255, 255, 0 }, { 0, 255, 255 }, { 255,
0, 255 }, { 192, 192, 192 }, { 0, 0, 0},
{ 200, 0, 0 }, { 0, 200, 0 }, { 0, 0, 200 }, { 200, 200, 0 }, { 0, 200, 200 }, { 200,
0, 200 }, { 100, 100, 100 }, { 200, 200, 200},
{ 100, 0, 0 }, { 0, 100, 0 }, { 0, 0, 100 }, { 100, 100, 0 }, { 0, 100, 100 }, { 100,
0, 100 }, { 50, 50, 50 }, { 100, 100, 100},
{ 50, 0, 0 }, { 0, 50, 0 }, { 0, 0, 50 }, { 50, 50, 0 }, { 0, 50, 50 }, { 50,
0, 50 }, { 25, 25, 25 }, { 50, 50, 50} };
SVGWriter2D::SVGWriter2D(MultiGridManagement2D management_): management(management_)
{}
void SVGWriter2D::writePatterns(){
plint numLevels = management.getNumLevels();
out << "<defs>\n";
for (plint iLevel=0; iLevel<numLevels; ++iLevel){
double size = 20.0*util::twoToThePower(-iLevel);
out << "<pattern id=\"Pat"<< size << "\" width=\""<< size <<
"\" height=\"" << size << "\" patternUnits=\"userSpaceOnUse\" >\n" <<
"\t<rect width=\"" << size << "\" height=\"" << size <<
"\" fill=\"none\" stroke=\"#000000\" stroke-width=\"2.0\" />\n</pattern>";
out << std::endl;
}
out << "</defs>\n";
}
void SVGWriter2D::writeDomainsWithDynamicsInfo(std::string fileName, int dynamicsNumber,
std::vector<MultiScalarField2D<int> > dynamicsInfo,
std::vector<std::map<int, std::string> >& idToName,
std::map<std::string,int>& nameToColor)
{
//std::vector<std::string> colors = createColors(dynamicsNumber);
out.open(fileName.c_str());
Box2D finestBoundingBox = management.getBoundingBox(management.getNumLevels()-1);
Dot2D size(finestBoundingBox.getNx(),finestBoundingBox.getNy());
writeHeader();
writePatterns();
for (plint iLevel=0; iLevel<management.getNumLevels(); ++iLevel){
// write each block of the current level
std::vector<Box2D> bulks = management.getBulks(iLevel);
double size = util::twoToThePower(-iLevel);
for (pluint iBlock=0; iBlock<bulks.size(); ++iBlock){
Box2D currentBlock = bulks[iBlock];
writeBG(currentBlock,size*20.0);
for (plint iX=currentBlock.x0; iX<=currentBlock.x1; ++iX){
for (plint iY=currentBlock.y0; iY<=currentBlock.y1; ++iY){
//std::string color = colors[dynamicsInfo[iLevel].get(iX,iY)];
int id = nameToColor[idToName[iLevel][dynamicsInfo[iLevel].get(iX,iY)]];
if ( id != -1 ) {
Array<double,2> location((double)iX*size*20.0,(double)iY*size*20.0);
if (id >= 128) id=127;
//writeRectangle(location, size, id);
// writeCircle(location, size*10.0, id);
//writeCircle(location, 7.0*size, id);
}
}
}
}
}
writeEnd();
}
void SVGWriter2D::writeBG(Box2D block, double size){
double height = block.y1-block.y0 == 0? -size : (double)(block.y1-block.y0)*size;
double width = block.x1-block.x0 == 0? -size :(double)(block.x1-block.x0)*size;
double x0 = (double)block.x0*size;
double y0 = (double)block.y0*size;
out << "<rect x=\"" << x0 << "\" y=\""<< y0 << "\" width=\"" << width << "\" height=\"" << height
<<"\" " << "style=\"stroke:black;fill:url(#Pat" << size << ")\"/>\n";
}
void SVGWriter2D::writeHeader(){
out << "<?xml version=\"1.0\" standalone=\"no\"?>\n";
out << "<!DOCTYPE svg PUBLIC"
<< " \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
out << "\t<svg width=\"100%\" height=\"100%\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">";
out << std::endl;
}
void SVGWriter2D::writeCircle(Array<double,2> location, double radius, int color){
PLB_ASSERT( color>=0 && color <128 );
out << "<circle cx=\"" << location[0] << "\" cy=\"" << location[1]
<< "\" r=\"" << radius << "\" style=\"stroke:none; " << "fill-opacity:0.5; "
<<"fill:" << "rgb(" << colors[color][0] << ","
<< colors[color][1] << "," << colors[color][2] << ")" << "\"/>" << std::endl;
}
void SVGWriter2D::writeEnd(){
out << "</svg>" << std::endl;
}
}; // namespace plb
hope I could help with this.
best,
Philippe