Multiple definition errors

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

Thank you very much for your feedback, Philippe. We always appreciate such useful input from the community. The bug will be corrected according to your suggestions in the next release.

Cheers,
Jonas