]> SALOME platform Git repositories - plugins/netgenplugin.git/blob - src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cxx
Salome HOME
0020676: EDF 1212 GEOM: Partition operation creates vertices which causes mesh comput...
[plugins/netgenplugin.git] / src / NETGENPlugin / NETGENPlugin_NETGEN_2D_ONLY.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File      : NETGENPlugin_NETGEN_2D_ONLY.cxx
23 // Author    : Edward AGAPOV (OCC)
24 // Project   : SALOME
25 //
26 #include "NETGENPlugin_NETGEN_2D_ONLY.hxx"
27
28 #include "NETGENPlugin_Mesher.hxx"
29
30 #include "SMDS_MeshElement.hxx"
31 #include "SMDS_MeshNode.hxx"
32 #include "SMESHDS_Mesh.hxx"
33 #include "SMESH_Comment.hxx"
34 #include "SMESH_Gen.hxx"
35 #include "SMESH_Mesh.hxx"
36 #include "SMESH_MesherHelper.hxx"
37 #include "StdMeshers_FaceSide.hxx"
38 #include "StdMeshers_MaxElementArea.hxx"
39 #include "StdMeshers_LengthFromEdges.hxx"
40 #include "StdMeshers_QuadranglePreference.hxx"
41
42 #include <Precision.hxx>
43 #include <Standard_ErrorHandler.hxx>
44 #include <Standard_Failure.hxx>
45
46 #include "utilities.h"
47
48 #include <list>
49 #include <vector>
50 #include <limits>
51
52 /*
53   Netgen include files
54 */
55 namespace nglib {
56 #include <nglib.h>
57 }
58 #define OCCGEOMETRY
59 #include <occgeom.hpp>
60 #include <meshing.hpp>
61 //#include <meshtype.hpp>
62 namespace netgen {
63   extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, int, int, char*);
64   /*extern*/ MeshingParameters mparam;
65 }
66
67 using namespace std;
68 using namespace netgen;
69 using namespace nglib;
70
71 //=============================================================================
72 /*!
73  *  
74  */
75 //=============================================================================
76
77 NETGENPlugin_NETGEN_2D_ONLY::NETGENPlugin_NETGEN_2D_ONLY(int hypId, int studyId,
78                                                          SMESH_Gen* gen)
79   : SMESH_2D_Algo(hypId, studyId, gen)
80 {
81   MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::NETGENPlugin_NETGEN_2D_ONLY");
82   _name = "NETGEN_2D_ONLY";
83   
84   _shapeType = (1 << TopAbs_FACE);// 1 bit /shape type
85
86   _compatibleHypothesis.push_back("MaxElementArea");
87   _compatibleHypothesis.push_back("LengthFromEdges");
88   _compatibleHypothesis.push_back("QuadranglePreference");
89
90   _hypMaxElementArea = 0;
91   _hypLengthFromEdges = 0;
92   _hypQuadranglePreference = 0;
93 }
94
95 //=============================================================================
96 /*!
97  *  
98  */
99 //=============================================================================
100
101 NETGENPlugin_NETGEN_2D_ONLY::~NETGENPlugin_NETGEN_2D_ONLY()
102 {
103   MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::~NETGENPlugin_NETGEN_2D_ONLY");
104 }
105
106 //=============================================================================
107 /*!
108  *  
109  */
110 //=============================================================================
111
112 bool NETGENPlugin_NETGEN_2D_ONLY::CheckHypothesis (SMESH_Mesh&         aMesh,
113                                                    const TopoDS_Shape& aShape,
114                                                    Hypothesis_Status&  aStatus)
115 {
116   _hypMaxElementArea = 0;
117   _hypLengthFromEdges = 0;
118   _hypQuadranglePreference = 0;
119
120   const list<const SMESHDS_Hypothesis*>& hyps = GetUsedHypothesis(aMesh, aShape, false);
121
122   if (hyps.empty())
123   {
124     aStatus = HYP_OK; //SMESH_Hypothesis::HYP_MISSING;
125     return true;  // (PAL13464) can work with no hypothesis, LengthFromEdges is default one
126   }
127
128   aStatus = HYP_MISSING;
129
130   list<const SMESHDS_Hypothesis*>::const_iterator ith;
131   for (ith = hyps.begin(); ith != hyps.end(); ++ith )
132   {
133     const SMESHDS_Hypothesis* hyp = (*ith);
134
135     string hypName = hyp->GetName();
136
137     if      ( hypName == "MaxElementArea")
138       _hypMaxElementArea = static_cast<const StdMeshers_MaxElementArea*> (hyp);
139     else if ( hypName == "LengthFromEdges" )
140       _hypLengthFromEdges = static_cast<const StdMeshers_LengthFromEdges*> (hyp);
141     else if ( hypName == "QuadranglePreference" )
142       _hypQuadranglePreference = static_cast<const StdMeshers_QuadranglePreference*>(hyp);
143     else {
144       aStatus = HYP_INCOMPATIBLE;
145       return false;
146     }
147   }
148
149   if ( _hypMaxElementArea && _hypLengthFromEdges ) {
150     aStatus = HYP_CONCURENT;
151     return false;
152   }
153
154   if ( _hypMaxElementArea || _hypLengthFromEdges || _hypQuadranglePreference)
155     aStatus = HYP_OK;
156
157   return aStatus == HYP_OK;
158 }
159
160 //================================================================================
161 /*!
162  * \brief Fill netgen mesh with segments
163   * \retval SMESH_ComputeErrorPtr - error description
164  */
165 //================================================================================
166
167 static TError AddSegmentsToMesh(netgen::Mesh&                    ngMesh,
168                                 OCCGeometry&                     geom,
169                                 const TSideVector&               wires,
170                                 SMESH_MesherHelper&              helper,
171                                 vector< const SMDS_MeshNode* > & nodeVec)
172 {
173   // ----------------------------
174   // Check wires and count nodes
175   // ----------------------------
176   int nbNodes = 0;
177   double totalLength = 0;
178   for ( int iW = 0; iW < wires.size(); ++iW )
179   {
180     StdMeshers_FaceSidePtr wire = wires[ iW ];
181     if ( wire->MissVertexNode() )
182       return TError
183         (new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH, "Missing nodes on vertices"));
184       
185     const vector<UVPtStruct>& uvPtVec = wire->GetUVPtStruct();
186     if ( uvPtVec.size() != wire->NbPoints() )
187       return TError
188         (new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH,
189                                 SMESH_Comment("Unexpected nb of points on wire ") << iW
190                                 << ": " << uvPtVec.size()<<" != "<<wire->NbPoints()));
191     nbNodes += wire->NbPoints();
192     totalLength += wire->Length();
193   }
194   nodeVec.reserve( nbNodes );
195
196   // -----------------
197   // Fill netgen mesh
198   // -----------------
199
200 //   netgen::Box<3> bb = geom.GetBoundingBox();
201 //   bb.Increase (bb.Diam()/10);
202 //   ngMesh.SetLocalH (bb.PMin(), bb.PMax(), 0.5); // set grading
203
204   const int faceID = 1, solidID = 0;
205   if ( ngMesh.GetNFD() < 1 )
206     ngMesh.AddFaceDescriptor (FaceDescriptor(faceID, solidID, solidID, 0));
207
208   for ( int iW = 0; iW < wires.size(); ++iW )
209   {
210     StdMeshers_FaceSidePtr wire = wires[ iW ];
211     const vector<UVPtStruct>& uvPtVec = wire->GetUVPtStruct();
212     const int nbSegments = wire->NbPoints() - 1;
213
214     int firstPointID = ngMesh.GetNP() + 1;
215     int edgeID = 1, posID = -2;
216     bool isInternalEdge = false;
217     for ( int i = 0; i < nbSegments; ++i ) // loop on segments
218     {
219       // Add the first point of a segment
220       const SMDS_MeshNode * n = uvPtVec[ i ].node;
221       const int posShapeID = n->GetPosition()->GetShapeId();
222
223       // skip nodes on degenerated edges
224       if ( helper.IsDegenShape( posShapeID ) &&
225            helper.IsDegenShape( uvPtVec[ i+1 ].node->GetPosition()->GetShapeId() ))
226         continue;
227
228       nodeVec.push_back( n );
229
230       MeshPoint mp( Point<3> (n->X(), n->Y(), n->Z()) );
231       ngMesh.AddPoint ( mp, 1, EDGEPOINT );
232
233       // Add the segment
234       Segment seg;
235
236 #ifdef NETGEN_NEW
237       seg.pnums[0] = ngMesh.GetNP();    // ng node id
238       seg.pnums[1] = seg.pnums[0] + 1;  // ng node id
239 #else
240       seg.p1 = ngMesh.GetNP();          // ng node id
241       seg.p2 = seg.p1 + 1;              // ng node id
242 #endif
243       seg.edgenr = ngMesh.GetNSeg() + 1;// segment id
244       seg.si = faceID;                  // = geom.fmap.FindIndex (face);
245
246       for ( int iEnd = 0; iEnd < 2; ++iEnd)
247       {
248         const UVPtStruct& pnt = uvPtVec[ i + iEnd ];
249
250         seg.epgeominfo[ iEnd ].dist = pnt.param; // param on curve
251         seg.epgeominfo[ iEnd ].u    = pnt.u;
252         seg.epgeominfo[ iEnd ].v    = pnt.v;
253
254         // find out edge id and node parameter on edge
255         bool onVertex = ( pnt.node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX );
256         if ( onVertex || posShapeID != posID )
257         {
258           // get edge id
259           double normParam = pnt.normParam;
260           if ( onVertex )
261             normParam = 0.5 * ( uvPtVec[ i ].normParam + uvPtVec[ i+1 ].normParam );
262           const TopoDS_Edge& edge = wire->Edge( wire->EdgeIndex( normParam ));
263           edgeID = geom.emap.FindIndex( edge );
264           posID  = posShapeID;
265           isInternalEdge = ( edge.Orientation() == TopAbs_INTERNAL );
266           if ( onVertex ) // param on curve is different on each of two edges
267             seg.epgeominfo[ iEnd ].dist = helper.GetNodeU( edge, pnt.node );
268         }
269         seg.epgeominfo[ iEnd ].edgenr = edgeID; //  = geom.emap.FindIndex(edge);
270       }
271
272       ngMesh.AddSegment (seg);
273
274 //       cout << "Segment: " << seg.edgenr << endl
275 //            << "\tp1: " << seg.p1 << endl
276 //            << "\tp2: " << seg.p2 << endl
277 //            << "\tp0 param: " << seg.epgeominfo[ 0 ].dist << endl
278 //            << "\tp0 uv: " << seg.epgeominfo[ 0 ].u <<", "<< seg.epgeominfo[ 0 ].v << endl
279 //            << "\tp0 edge: " << seg.epgeominfo[ 0 ].edgenr << endl
280 //            << "\tp1 param: " << seg.epgeominfo[ 1 ].dist << endl
281 //            << "\tp1 uv: " << seg.epgeominfo[ 1 ].u <<", "<< seg.epgeominfo[ 1 ].v << endl
282 //            << "\tp1 edge: " << seg.epgeominfo[ 1 ].edgenr << endl;
283
284       if ( isInternalEdge )
285       {
286 #ifdef NETGEN_NEW
287         swap (seg.pnums[0], seg.pnums[1]);
288 #else
289         swap (seg.p1, seg.p2);
290 #endif
291         swap( seg.epgeominfo[0], seg.epgeominfo[1] );
292         seg.edgenr = ngMesh.GetNSeg() + 1; // segment id
293         ngMesh.AddSegment (seg);
294       }
295     } // loop on segments on a wire
296
297     // close chain of segments
298     bool isClosedWire = ( wire->FirstVertex().IsSame( wire->LastVertex() ));
299     if ( isClosedWire )
300     {
301       Segment& seg = ngMesh.LineSegment( ngMesh.GetNSeg() );
302 #ifdef NETGEN_NEW
303       seg.pnums[1] = firstPointID;
304 #else
305       seg.p2 = firstPointID;
306 #endif
307     }
308     else // INTERNAL wire (Issue 0020676)
309     {
310       const SMDS_MeshNode * n = uvPtVec.back().node;
311       nodeVec.push_back( n );
312
313       MeshPoint mp( Point<3> (n->X(), n->Y(), n->Z()) );
314       ngMesh.AddPoint ( mp, 1, EDGEPOINT );
315     }
316
317   } // loop on wires of a face
318
319   // add a segment instead of internal vertex
320   NETGENPlugin_Internals intShapes( *helper.GetMesh(), helper.GetSubShape(), /*is3D=*/false );
321   NETGENPlugin_Mesher::addIntVerticesInFaces( geom, ngMesh, nodeVec, intShapes );
322
323   ngMesh.CalcSurfacesOfNode();
324
325   return TError();
326 }
327
328 //=============================================================================
329 /*!
330  *Here we are going to use the NETGEN mesher
331  */
332 //=============================================================================
333
334 bool NETGENPlugin_NETGEN_2D_ONLY::Compute(SMESH_Mesh&         aMesh,
335                                           const TopoDS_Shape& aShape)
336 {
337   MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::Compute()");
338
339   SMESHDS_Mesh* meshDS = aMesh.GetMeshDS();
340   int faceID = meshDS->ShapeToIndex( aShape );
341
342   SMESH_MesherHelper helper(aMesh);
343   _quadraticMesh = helper.IsQuadraticSubMesh(aShape);
344   helper.SetElementsOnShape( true );
345   const bool ignoreMediumNodes = _quadraticMesh;
346   
347   // ------------------------
348   // get all edges of a face
349   // ------------------------
350   const TopoDS_Face F = TopoDS::Face( aShape.Oriented( TopAbs_FORWARD ));
351   TError problem;
352   TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, problem );
353   if ( problem && !problem->IsOK() )
354     return error( problem );
355   int nbWires = wires.size();
356   if ( nbWires == 0 )
357     return error( "Problem in StdMeshers_FaceSide::GetFaceWires()");
358   if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments
359     return error(COMPERR_BAD_INPUT_MESH,
360                  SMESH_Comment("Too few segments: ")<<wires[0]->NbSegments());
361
362   // -------------------------
363   // Make input netgen mesh
364   // -------------------------
365
366   NETGENPlugin_NetgenLibWrapper ngLib;
367   netgen::Mesh * ngMesh = (netgen::Mesh*) ngLib._ngMesh;
368
369   netgen::OCCGeometry occgeo;
370   NETGENPlugin_Mesher::PrepareOCCgeometry( occgeo, F, aMesh );
371   occgeo.fmap.Clear(); // face can be reversed, which is wrong in this case (issue 19978)
372   occgeo.fmap.Add( F );
373
374   vector< const SMDS_MeshNode* > nodeVec;
375   problem = AddSegmentsToMesh( *ngMesh, occgeo, wires, helper, nodeVec );
376   if ( problem && !problem->IsOK() )
377     return error( problem );
378
379   // --------------------
380   // compute edge length
381   // --------------------
382
383   double edgeLength = 0;
384   if (_hypLengthFromEdges || !_hypLengthFromEdges && !_hypMaxElementArea)
385   {
386     int nbSegments = 0;
387     for ( int iW = 0; iW < nbWires; ++iW )
388     {
389       edgeLength += wires[ iW ]->Length();
390       nbSegments += wires[ iW ]->NbSegments();
391     }
392     if ( nbSegments )
393       edgeLength /= nbSegments;
394   }
395   if ( _hypMaxElementArea )
396   {
397     double maxArea = _hypMaxElementArea->GetMaxArea();
398     edgeLength = sqrt(2. * maxArea/sqrt(3.0));
399   }
400   if ( edgeLength < DBL_MIN )
401     edgeLength = occgeo.GetBoundingBox().Diam();
402
403   //cout << " edgeLength = " << edgeLength << endl;
404
405   netgen::mparam.maxh = edgeLength;
406   netgen::mparam.quad = _hypQuadranglePreference ? 1 : 0;
407   //ngMesh->SetGlobalH ( edgeLength );
408
409   // -------------------------
410   // Generate surface mesh
411   // -------------------------
412
413   char *optstr = 0;
414   int startWith = MESHCONST_MESHSURFACE;
415   int endWith   = MESHCONST_OPTSURFACE;
416   int err = 1;
417
418   try {
419 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
420     OCC_CATCH_SIGNALS;
421 #endif
422     err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
423   }
424   catch (Standard_Failure& ex) {
425     string comment = ex.DynamicType()->Name();
426     if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) {
427       comment += ": ";
428       comment += ex.GetMessageString();
429     }
430     error(COMPERR_OCC_EXCEPTION, comment);
431   }
432   catch (NgException exc) {
433     error( SMESH_Comment("NgException: ") << exc.What() );
434   }
435   catch (...) {
436     error(COMPERR_EXCEPTION,"Exception in netgen::OCCGenerateMesh()");
437   }
438
439   // ----------------------------------------------------
440   // Fill the SMESHDS with the generated nodes and faces
441   // ----------------------------------------------------
442
443   int nbNodes = ngMesh->GetNP();
444   int nbFaces = ngMesh->GetNSE();
445
446   int nbInputNodes = nodeVec.size();
447   nodeVec.resize( nbNodes, 0 );
448
449   // add nodes
450   for ( int i = nbInputNodes + 1; i <= nbNodes; ++i )
451   {
452     const MeshPoint& ngPoint = ngMesh->Point(i);
453 #ifdef NETGEN_NEW
454     SMDS_MeshNode * node = meshDS->AddNode(ngPoint(0), ngPoint(1), ngPoint(2));
455 #else
456     SMDS_MeshNode * node = meshDS->AddNode(ngPoint.X(), ngPoint.Y(), ngPoint.Z());
457 #endif
458     nodeVec[ i-1 ] = node;
459   }
460
461   // create faces
462   bool reverse = ( aShape.Orientation() == TopAbs_REVERSED );
463   for ( int i = 1; i <= nbFaces ; ++i )
464   {
465     const Element2d& elem = ngMesh->SurfaceElement(i);
466     vector<const SMDS_MeshNode*> nodes( elem.GetNP() );
467     for (int j=1; j <= elem.GetNP(); ++j)
468     {
469       int pind = elem.PNum(j);
470       const SMDS_MeshNode* node = nodeVec.at(pind-1);
471       if ( reverse )
472         nodes[ nodes.size()-j ] = node;
473       else
474         nodes[ j-1 ] = node;
475       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE )
476       {
477         const PointGeomInfo& pgi = elem.GeomInfoPi(j);
478         meshDS->SetNodeOnFace((SMDS_MeshNode*)node, faceID, pgi.u, pgi.v);
479       }
480     }
481     SMDS_MeshFace* face = 0;
482     if ( elem.GetType() == TRIG )
483       face = helper.AddFace(nodes[0],nodes[1],nodes[2]);
484     else
485       face = helper.AddFace(nodes[0],nodes[1],nodes[2],nodes[3]);
486   }
487
488   return !err;
489 }
490
491
492 //=============================================================================
493 /*!
494  *
495  */
496 //=============================================================================
497
498 bool NETGENPlugin_NETGEN_2D_ONLY::Evaluate(SMESH_Mesh& aMesh,
499                                            const TopoDS_Shape& aShape,
500                                            MapShapeNbElems& aResMap)
501 {
502   TopoDS_Face F = TopoDS::Face(aShape);
503   if(F.IsNull())
504     return false;
505
506   // collect info from edges
507   int nb0d = 0, nb1d = 0;
508   bool IsQuadratic = false;
509   bool IsFirst = true;
510   double fullLen = 0.0;
511   TopTools_MapOfShape tmpMap;
512   for (TopExp_Explorer exp(F, TopAbs_EDGE); exp.More(); exp.Next()) {
513     TopoDS_Edge E = TopoDS::Edge(exp.Current());
514     if( tmpMap.Contains(E) )
515       continue;
516     tmpMap.Add(E);
517     SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current());
518     MapShapeNbElemsItr anIt = aResMap.find(aSubMesh);
519     if( anIt==aResMap.end() ) {
520       SMESH_subMesh *sm = aMesh.GetSubMesh(F);
521       SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
522       smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
523       return false;
524     }
525     std::vector<int> aVec = (*anIt).second;
526     nb0d += aVec[SMDSEntity_Node];
527     nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
528     double aLen = SMESH_Algo::EdgeLength(E);
529     fullLen += aLen;
530     if(IsFirst) {
531       IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]);
532       IsFirst = false;
533     }
534   }
535   tmpMap.Clear();
536
537   // compute edge length
538   double ELen = 0;
539   if (_hypLengthFromEdges || !_hypLengthFromEdges && !_hypMaxElementArea) {
540     if ( nb1d > 0 )
541       ELen = fullLen / nb1d;
542   }
543   if ( _hypMaxElementArea ) {
544     double maxArea = _hypMaxElementArea->GetMaxArea();
545     ELen = sqrt(2. * maxArea/sqrt(3.0));
546   }
547   GProp_GProps G;
548   BRepGProp::SurfaceProperties(F,G);
549   double anArea = G.Mass();
550
551   const int hugeNb = numeric_limits<int>::max()/10;
552   if ( anArea / hugeNb > ELen*ELen )
553   {
554     SMESH_subMesh *sm = aMesh.GetSubMesh(F);
555     SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
556     smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated.\nToo small element length",this));
557     return false;
558   }
559   int nbFaces = (int) ( anArea / ( ELen*ELen*sqrt(3.) / 4 ) );
560   int nbNodes = (int) ( ( nbFaces*3 - (nb1d-1)*2 ) / 6 + 1 );
561   std::vector<int> aVec(SMDSEntity_Last);
562   for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
563   if( IsQuadratic ) {
564     aVec[SMDSEntity_Node] = nbNodes;
565     aVec[SMDSEntity_Quad_Triangle] = nbFaces;
566   }
567   else {
568     aVec[SMDSEntity_Node] = nbNodes;
569     aVec[SMDSEntity_Triangle] = nbFaces;
570   }
571   SMESH_subMesh *sm = aMesh.GetSubMesh(F);
572   aResMap.insert(std::make_pair(sm,aVec));
573
574   return true;
575 }