BRepMesh_IncrementalMesh

Dear all,

 

I am writing to ask for advice, if anyone has got any, regarding my usage of the BRepMesh_Incremental class. I have built a small working example I am trying to use to debug my code but I cannot get my head around it. Basically, my problem is the following: given a std::vector<TopoDS_Face> mesh them running a parallel for loop using the BRepMesh_IncrementalMesh in parallel. The small code I have written is posted hereafter:

 

   Standard_Real tolerance = 0.25;
   Standard_Real angular_tolerance = 0.5;
   Standard_Real minTriangleSize = Precision::Confusion();

   BRepMesh_IncrementalMesh::SetParallelDefault(Standard_True);
   Concurrency::parallel_for_each(facesToTessellate.begin(), facesToTessellate.end(), [&](TopoDS_Face pFace)
   {

      BRepMesh_IncrementalMesh ocmesher;
      ocmesher.SetControlSurfaceDeflection(Standard_False);
      ocmesher.SetParallel(Standard_True);

      ocmesher.SetShape(pFace);
      ocmesher.SetDeflection(tolerance);
      ocmesher.SetMinSize(minTriangleSize);
      ocmesher.SetInternalVerticesMode(Standard_False);
      ocmesher.SetRelative(Standard_False);
      ocmesher.SetAngle(angular_tolerance);

      ocmesher.Perform();

}

The thing that puzzles me is that this the for loop does not always hangs but sometimes it works and I get through it but some others, the application hangs and I do not get out of the for loop. I have checked and all the faces I am working with are valid shapes with no errors. Does it look to you I am doing something clearly wrong? 

I have been reading some threads about  BRepMesh_IncrementalMesh and it might hangs sometimes. This is why I set  SetControlSurfaceDeflection to false and I have tried using a much higher minTriangleSize. 

 

I would deeply appreciate any help.

Thank you in advance for any help,

Kind regards,

Paolo Tricerri

 

Paolo Tricerri's picture

Hello all,

apparently, using BRepMesh_FastDiscret instead of BRepMesh_IncrementalMesh stops the small application from randomly hanging. It's not a bug fix and I still have to evaluate the resulting mesh but it seems to be a workaround.

Any suggestion is more than welcome, still.

Thank you very much,

Kind regards,

Paolo

Roman Lygin's picture

Hi Paolo,
 

Let me offer a few comments:

1. The most likely reason of the behavior you observe is data races for face triangulations or edge polygons. Even if the code looks correct it may work incorrectly on shared data. The races for face triangulations can be if you have IsSame() or IsPartner() faces, i.e. sharing the same BRep_TFace which contains Poly_Triangulation.

Races for edges (which can be much more probable) can be if your faces share edges. For instance, if you explored a shell (solid) and put into this vector you will certainly have races.
 

There are tools to detect data races so you might want to try. We prefer Intel Inspector XE but perhaps your choice could be different.
 

To run BRepMeshes in parallel you must ensure no shared edges between individual elements. Below is the excerpt from our code from the test library to quickly check that. Feel free to reuse/adjust.

2. When you triangulate faces independently you will get a non water-tight mesh as boundaries will be meshed individually. Perhaps that's not an issue but make sure you understand that.

3. Using FastDiscret vs IncrementalMesh should have no impact, as the latter just calls the former. So even if you currently do not observe sporadic crashes/hangs/etc, this could be pure luck.
 

4. You might want to revisit your approach depending on what objective you are trying to achieve and what data you are working with. If you work with solids or shells, just invoke BRepMesher on it with enabled SetParallel() and let it do the work. If you work with individual shapes (faces) first sort them out into individual groups without shared subshapes between each other and then apply your code.
 

Good luck!

Roman

//This is our specific API, ignore that and just get the idea.
/*! Returns true if there are at least two bodies that have common subshapes.*/
bool HasSharedTopology (const ModelData_Model& theModel)
{
   
    ModelG_WriterHelper::PartVecType aVec;
    ModelData_SceneGraphElementAnyFilter aFilter;
    ModelG_WriterHelper::AccumulateParts (theModel, aFilter, aVec, true /*theUniqueParts*/);

    cadex_unordered_set<TopoDS_Shape>::type aSet; //std::unordered_set with hasher/equal based on using TopoDS::IsSame(), you can substitute with TopTools_MapOfShape
    bool aHasBRep = false;
    const TopLoc_Location aLoc0;

    for (size_t i = 0; i < aVec.size(); ++i) {
        const auto& aPart = aVec[i].first;
        auto aBRep = aPart.BRepRepresentation();
        if (!aBRep)
            continue;
        aHasBRep = true;

        const auto& aBodyList = aBRep.Get();
        for (size_t j = 0; j < aBodyList.Size(); ++j) {
            const auto& aBody          = aBodyList[j];
            const TopoDS_Shape& aShape = aBody;

            TopTools_IndexedMapOfShape aSMap, aPMap; //map of unique shapes (not IsSame, IsPartner)
            TopExp::MapShapes (aShape, aSMap);

            for (int k = 1; k <= aSMap.Extent(); ++k) {
                aPMap.Add (aSMap(k).Located (aLoc0));
            }

            //now check if aPMap contains any subshapes already available in aSet
            for (int k = 1; k <= aPMap.Extent(); ++k) {
                const auto& aSubshape = aPMap (k);
                auto r = aSet.insert (aSubshape);
                if (!r.second)
                    return true;
            }
        }
    }
    if (!aHasBRep)
        return false; //ensure that at least one B-Rep was encountered

    return false;
}

Paolo Tricerri's picture

Hi Roman,

thanks for the very interesting reply. I will investigate the shape I have! Actually I also thought that by simply switching to the BRepMesh_FastDiscret class was more a matter of luck rather than a bug fix. 

Thanks a lot for the moment!

Kind regards,

Paolo