Salome HOME
Modifications to properly handle parallel compute for 2D
[modules/smesh.git] / src / SMESH / SMESH_Gen.cxx
1 // Copyright (C) 2007-2023  CEA, EDF, 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, or (at your option) any later version.
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
23 //  SMESH SMESH : implementation of SMESH idl descriptions
24 //  File   : SMESH_Gen.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : SMESH
27 //
28 //#define CHRONODEF
29 //
30 #include "SMESH_Gen.hxx"
31
32 #include "SMESH_DriverMesh.hxx"
33 #include "SMDS_Mesh.hxx"
34 #include "SMDS_MeshElement.hxx"
35 #include "SMDS_MeshNode.hxx"
36 #include "SMESHDS_Document.hxx"
37 #include "SMESH_HypoFilter.hxx"
38 #include "SMESH_Mesh.hxx"
39 #include "SMESH_SequentialMesh.hxx"
40 #include "SMESH_ParallelMesh.hxx"
41 #include "SMESH_MesherHelper.hxx"
42 #include "SMESH_subMesh.hxx"
43
44 #include <utilities.h>
45 #include <Utils_ExceptHandlers.hxx>
46
47 #include <TopExp_Explorer.hxx>
48 #include <TopoDS.hxx>
49 #include <TopoDS_Iterator.hxx>
50
51 #include "memoire.h"
52 #include <functional>
53
54 #include <QString>
55 #include <QProcess>
56
57 #ifdef WIN32
58   #include <windows.h>
59 #endif
60
61 #include <Basics_Utils.hxx>
62
63 #ifndef WIN32
64 #include <boost/asio.hpp>
65 #endif
66
67 using namespace std;
68 #ifndef WIN32
69 #include <boost/filesystem.hpp>
70 namespace fs = boost::filesystem;
71 #endif
72
73 // Environment variable separator
74 #ifdef WIN32
75   #define env_sep ';'
76 #else
77   #define env_sep ':'
78 #endif
79
80 namespace
81 {
82   // a structure used to nullify SMESH_Gen field of SMESH_Hypothesis,
83   // which is needed for SMESH_Hypothesis not deleted before ~SMESH_Gen()
84   struct _Hyp : public SMESH_Hypothesis
85   {
86     void NullifyGen()
87     {
88       _gen = 0;
89     }
90   };
91
92   //================================================================================
93   /*!
94    * \brief Fill a map of shapes with all sub-shape of a sub-mesh
95    */
96   //================================================================================
97
98   TopTools_IndexedMapOfShape * fillAllowed( SMESH_subMesh*               sm,
99                                             const bool                   toFill,
100                                             TopTools_IndexedMapOfShape * allowedSub )
101   {
102     if ( !toFill || !allowedSub )
103     {
104       return nullptr;
105     }
106     if ( allowedSub->IsEmpty() )
107     {
108       allowedSub->ReSize( sm->DependsOn().size() + 1 );
109       allowedSub->Add( sm->GetSubShape() );
110       for ( const auto & key_sm : sm->DependsOn() )
111         allowedSub->Add( key_sm.second->GetSubShape() );
112     }
113     return allowedSub;
114   }
115 }
116
117 //=============================================================================
118 /*!
119  *  Constructor
120  */
121 //=============================================================================
122
123 SMESH_Gen::SMESH_Gen()
124 {
125   _studyContext = new StudyContextStruct;
126   _studyContext->myDocument = new SMESHDS_Document();
127   _localId = 0;
128   _hypId   = 0;
129   _segmentation = _nbSegments = 10;
130   _compute_canceled = false;
131 }
132
133 //=============================================================================
134 /*!
135  * Destructor
136  */
137 //=============================================================================
138
139 SMESH_Gen::~SMESH_Gen()
140 {
141   std::map < int, SMESH_Hypothesis * >::iterator i_hyp = _studyContext->mapHypothesis.begin();
142   for ( ; i_hyp != _studyContext->mapHypothesis.end(); ++i_hyp )
143   {
144     if ( _Hyp* h = static_cast< _Hyp*>( i_hyp->second ))
145       h->NullifyGen();
146   }
147   delete _studyContext->myDocument;
148   delete _studyContext;
149 }
150
151 //=============================================================================
152 /*!
153  * Creates a mesh in a study.
154  * if (theIsEmbeddedMode) { mesh modification commands are not logged }
155  */
156 //=============================================================================
157
158 SMESH_Mesh* SMESH_Gen::CreateMesh(bool theIsEmbeddedMode)
159 {
160   Unexpect aCatch(SalomeException);
161
162   // create a new SMESH_mesh object
163   SMESH_Mesh *aMesh = new SMESH_SequentialMesh(
164                                      _localId++,
165                                      this,
166                                      theIsEmbeddedMode,
167                                      _studyContext->myDocument);
168   _studyContext->mapMesh[_localId-1] = aMesh;
169
170   return aMesh;
171 }
172
173 //=============================================================================
174 /*!
175  * Creates a parallel mesh in a study.
176  * if (theIsEmbeddedMode) { mesh modification commands are not logged }
177  */
178 //=============================================================================
179
180 SMESH_ParallelMesh* SMESH_Gen::CreateParallelMesh(bool theIsEmbeddedMode)
181 {
182   Unexpect aCatch(SalomeException);
183
184   // create a new SMESH_mesh object
185   SMESH_ParallelMesh *aMesh = new SMESH_ParallelMesh(
186                                      _localId++,
187                                      this,
188                                      theIsEmbeddedMode,
189                                      _studyContext->myDocument);
190   _studyContext->mapMesh[_localId-1] = aMesh;
191
192   return aMesh;
193 }
194
195 //=============================================================================
196 /*!
197  * Algo to run the computation of all the submeshes of a mesh in sequentila
198  */
199 //=============================================================================
200
201 bool SMESH_Gen::sequentialComputeSubMeshes(
202           SMESH_Mesh & aMesh,
203           const TopoDS_Shape & aShape,
204           const ::MeshDimension       aDim,
205           TSetOfInt*                  aShapesId /*=0*/,
206           TopTools_IndexedMapOfShape* allowedSubShapes,
207           SMESH_subMesh::compute_event &computeEvent,
208           const bool includeSelf,
209           const bool complexShapeFirst,
210           const bool   aShapeOnly)
211 {
212   MESSAGE("Sequential Compute of submeshes");
213
214   bool ret = true;
215
216   SMESH_subMeshIteratorPtr smIt;
217   SMESH_subMesh *shapeSM = aMesh.GetSubMesh(aShape);
218
219   smIt = shapeSM->getDependsOnIterator(includeSelf, !complexShapeFirst);
220   while ( smIt->more() )
221   {
222     SMESH_subMesh* smToCompute = smIt->next();
223
224     // do not mesh vertices of a pseudo shape
225     const TopoDS_Shape&        shape = smToCompute->GetSubShape();
226     const TopAbs_ShapeEnum shapeType = shape.ShapeType();
227     if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX )
228       continue;
229
230     // check for preview dimension limitations
231     if ( aShapesId && SMESH_Gen::GetShapeDim( shapeType ) > (int)aDim )
232     {
233       // clear compute state not to show previous compute errors
234       //  if preview invoked less dimension less than previous
235       smToCompute->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
236       continue;
237     }
238
239     if (smToCompute->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE)
240     {
241       if (_compute_canceled)
242         return false;
243       smToCompute->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
244       setCurrentSubMesh( smToCompute );
245       smToCompute->ComputeStateEngine( computeEvent );
246       setCurrentSubMesh( nullptr );
247       smToCompute->SetAllowedSubShapes( nullptr );
248     }
249
250     // we check all the sub-meshes here and detect if any of them failed to compute
251     if (smToCompute->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE &&
252         ( shapeType != TopAbs_EDGE || !SMESH_Algo::isDegenerated( TopoDS::Edge( shape ))))
253       ret = false;
254     else if ( aShapesId )
255       aShapesId->insert( smToCompute->GetId() );
256   }
257   //aMesh.GetMeshDS()->Modified();
258   return ret;
259
260 };
261
262 //=============================================================================
263 /*
264  * compute of a submesh
265  * This function is passed to the thread pool
266  */
267 //=============================================================================
268 const std::function<void(SMESH_subMesh*,
269                          SMESH_subMesh::compute_event,
270                          SMESH_subMesh*,
271                          bool,
272                          TopTools_IndexedMapOfShape *,
273                          TSetOfInt*)>
274      compute_function([] (SMESH_subMesh* sm,
275                           SMESH_subMesh::compute_event event,
276                           SMESH_subMesh *shapeSM,
277                           bool aShapeOnly,
278                           TopTools_IndexedMapOfShape *allowedSubShapes,
279                           TSetOfInt*                  aShapesId) -> void
280 {
281   if (sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE)
282   {
283     sm->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
284     //setCurrentSubMesh( sm );
285     sm->ComputeStateEngine(event);
286     //setCurrentSubMesh( nullptr );
287     sm->SetAllowedSubShapes( nullptr );
288   }
289
290   if ( aShapesId )
291     aShapesId->insert( sm->GetId() );
292
293 });
294
295
296 //=============================================================================
297 /*
298  * Copy a file on remote resource
299  */
300 //=============================================================================
301
302 void SMESH_Gen::send_mesh(SMESH_Mesh& aMesh, std::string file_name)
303 {
304 #ifndef WIN32
305   SMESH_ParallelMesh& aParMesh = dynamic_cast<SMESH_ParallelMesh&>(aMesh);
306   // Calling run_mesher
307   // Path to mesher script
308   fs::path send_files = fs::path(std::getenv("SMESH_ROOT_DIR"))/
309   fs::path("bin")/
310   fs::path("salome")/
311   fs::path("send_files.py");
312
313   std::string s_program="python3";
314   std::list<std::string> params;
315   params.push_back(send_files.string());
316   params.push_back(file_name);
317   params.push_back("--resource="+aParMesh.GetResource());
318
319   // log file
320   fs::path log_file=aParMesh.GetTmpFolder() / fs::path("copy.log");
321   QString out_file = log_file.string().c_str();
322
323   // Building arguments for QProcess
324   QString program = QString::fromStdString(s_program);
325   QStringList arguments;
326   for(auto arg : params){
327     arguments << arg.c_str();
328   }
329
330   std::string cmd = "";
331   cmd += s_program;
332   for(auto arg: params){
333     cmd += " " + arg;
334   }
335   MESSAGE("Send files command: ");
336   MESSAGE(cmd);
337
338   QProcess myProcess;
339   myProcess.setProcessChannelMode(QProcess::MergedChannels);
340   myProcess.setStandardOutputFile(out_file);
341
342   myProcess.start(program, arguments);
343   // Waiting for process to finish (argument -1 make it wait until the end of
344   // the process otherwise it just waits 30 seconds)
345   bool finished = myProcess.waitForFinished(-1);
346   int ret = myProcess.exitCode();
347
348   if(ret != 0 || !finished){
349   // Run crahed
350     std::string msg = "Issue with send_files: \n";
351     msg += "See log for more details: " + log_file.string() + "\n";
352     msg += cmd + "\n";
353     throw SALOME_Exception(msg);
354   }
355 #endif
356 }
357
358 //=============================================================================
359 /*!
360  * Algo to run the computation of all the submeshes of a mesh in parallel
361  */
362 //=============================================================================
363
364 bool SMESH_Gen::parallelComputeSubMeshes(
365           SMESH_Mesh & aMesh,
366           const TopoDS_Shape & aShape,
367           const ::MeshDimension       aDim,
368           TSetOfInt*                  aShapesId /*=0*/,
369           TopTools_IndexedMapOfShape* allowedSubShapes,
370           SMESH_subMesh::compute_event &computeEvent,
371           const bool includeSelf,
372           const bool complexShapeFirst,
373           const bool   aShapeOnly)
374 {
375 #ifdef WIN32
376   throw SALOME_Exception("ParallelMesh is not working on Windows");
377 #else
378
379   bool ret = true;
380
381   SMESH_subMeshIteratorPtr smIt;
382   SMESH_subMesh *shapeSM = aMesh.GetSubMesh(aShape);
383   SMESH_ParallelMesh &aParMesh = dynamic_cast<SMESH_ParallelMesh&>(aMesh);
384
385   TopAbs_ShapeEnum previousShapeType = TopAbs_VERTEX;
386   MESSAGE("Parallel Compute of submeshes");
387
388
389   smIt = shapeSM->getDependsOnIterator(includeSelf, !complexShapeFirst);
390   while ( smIt->more() )
391   {
392     SMESH_subMesh* smToCompute = smIt->next();
393
394     // do not mesh vertices of a pseudo shape
395     const TopoDS_Shape&        shape = smToCompute->GetSubShape();
396     const TopAbs_ShapeEnum shapeType = shape.ShapeType();
397     // Not doing in parallel 1D meshes
398     if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX )
399       continue;
400
401     if (shapeType != previousShapeType) {
402       // Waiting for all threads for the previous type to end
403       aMesh.wait();
404
405       std::string file_name="";
406       if (previousShapeType == aParMesh.GetDumpElement())
407         file_name = "Mesh"+std::to_string(aParMesh.GetParallelismDimension()-1)+"D.med";
408
409       if(file_name != "")
410       {
411         fs::path mesh_file = fs::path(aParMesh.GetTmpFolder()) / fs::path(file_name);
412               SMESH_DriverMesh::exportMesh(mesh_file.string(), aMesh, "MESH");
413         if (aParMesh.GetParallelismMethod() == ParallelismMethod::MultiNode) {
414           this->send_mesh(aMesh, mesh_file.string());
415         }
416       }
417       //Resetting threaded pool info
418       previousShapeType = shapeType;
419     }
420
421     // check for preview dimension limitations
422     if ( aShapesId && SMESH_Gen::GetShapeDim( shapeType ) > (int)aDim )
423     {
424       // clear compute state not to show previous compute errors
425       //  if preview invoked less dimension less than previous
426       smToCompute->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
427       continue;
428     }
429     // Parallelism is only for 3D parts
430     if(shapeType!=aMesh.GetParallelElement()){
431       compute_function(smToCompute, computeEvent,
432                       shapeSM, aShapeOnly, allowedSubShapes,
433                       aShapesId);
434     }else{
435       boost::asio::post(*(aParMesh.GetPool()), std::bind(compute_function, smToCompute, computeEvent,
436                         shapeSM, aShapeOnly, allowedSubShapes,
437                         aShapesId));
438     }
439   }
440
441   // Waiting for the thread for Solids to finish
442   aMesh.wait();
443
444   aMesh.GetMeshDS()->Modified();
445
446   // Cleanup done here as in Python the destructor is not called
447   aParMesh.cleanup();
448
449   return ret;
450 #endif
451 };
452
453 //=============================================================================
454 /*
455  * Compute a mesh
456  */
457 //=============================================================================
458
459 bool SMESH_Gen::Compute(SMESH_Mesh &                aMesh,
460                         const TopoDS_Shape &        aShape,
461                         const int                   aFlags /*= COMPACT_MESH*/,
462                         const ::MeshDimension       aDim /*=::MeshDim_3D*/,
463                         TSetOfInt*                  aShapesId /*=0*/,
464                         TopTools_IndexedMapOfShape* anAllowedSubShapes/*=0*/)
465 {
466   MEMOSTAT;
467
468   const bool   aShapeOnly = aFlags & SHAPE_ONLY;
469   const bool     anUpward = aFlags & UPWARD;
470   const bool aCompactMesh = aFlags & COMPACT_MESH;
471
472   bool ret = true;
473
474   SMESH_subMesh *sm, *shapeSM = aMesh.GetSubMesh(aShape);
475
476   const bool includeSelf = true;
477   const bool complexShapeFirst = true;
478   const int  globalAlgoDim = 100;
479
480   SMESH_subMeshIteratorPtr smIt;
481
482   // Fix of Issue 22150. Due to !BLSURF->OnlyUnaryInput(), BLSURF computes edges
483   // that must be computed by Projection 1D-2D while the Projection asks to compute
484   // one face only.
485   SMESH_subMesh::compute_event computeEvent =
486     aShapeOnly ? SMESH_subMesh::COMPUTE_SUBMESH : SMESH_subMesh::COMPUTE;
487   if ( !aMesh.HasShapeToMesh() )
488     computeEvent = SMESH_subMesh::COMPUTE_NOGEOM; // if several algos and no geometry
489
490   TopTools_IndexedMapOfShape *allowedSubShapes = anAllowedSubShapes, allowedSub;
491   if ( aShapeOnly && !allowedSubShapes )
492     allowedSubShapes = &allowedSub;
493
494   if ( anUpward ) // is called from the below code in this method
495   {
496     // ===============================================
497     // Mesh all the sub-shapes starting from vertices
498     // ===============================================
499     ret = aMesh.ComputeSubMeshes(
500             this,
501             aMesh, aShape, aDim,
502             aShapesId, allowedSubShapes,
503             computeEvent,
504             includeSelf,
505             complexShapeFirst,
506             aShapeOnly);
507
508     return ret;
509   }
510   else
511   {
512     // ================================================================
513     // Apply algos that do NOT require discretized boundaries
514     // ("all-dimensional") and do NOT support sub-meshes, starting from
515     // the most complex shapes and collect sub-meshes with algos that
516     // DO support sub-meshes
517     // ================================================================
518     list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes[4]; // for each dim
519
520     // map to sort sm with same dim algos according to dim of
521     // the shape the algo assigned to (issue 0021217).
522     // Other issues influenced the algo applying order:
523     // 21406, 21556, 21893, 20206
524     multimap< int, SMESH_subMesh* > shDim2sm;
525     multimap< int, SMESH_subMesh* >::reverse_iterator shDim2smIt;
526     TopoDS_Shape algoShape;
527     int prevShapeDim = -1, aShapeDim;
528
529     smIt = shapeSM->getDependsOnIterator(includeSelf, complexShapeFirst);
530     while ( smIt->more() )
531     {
532       SMESH_subMesh* smToCompute = smIt->next();
533       if ( smToCompute->GetComputeState() != SMESH_subMesh::READY_TO_COMPUTE )
534         continue;
535
536       const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
537       aShapeDim = GetShapeDim( aSubShape );
538       if ( aShapeDim < 1 ) break;
539
540       // check for preview dimension limitations
541       if ( aShapesId && aShapeDim > (int)aDim )
542         continue;
543
544       SMESH_Algo* algo = GetAlgo( smToCompute, &algoShape );
545       if ( algo && !algo->NeedDiscreteBoundary() )
546       {
547         if ( algo->SupportSubmeshes() )
548         {
549           // reload sub-meshes from shDim2sm into smWithAlgoSupportingSubmeshes
550           // so that more local algos to go first
551           if ( prevShapeDim != aShapeDim )
552           {
553             prevShapeDim = aShapeDim;
554             for ( shDim2smIt = shDim2sm.rbegin(); shDim2smIt != shDim2sm.rend(); ++shDim2smIt )
555               if ( shDim2smIt->first == globalAlgoDim )
556                 smWithAlgoSupportingSubmeshes[ aShapeDim ].push_back( shDim2smIt->second );
557               else
558                 smWithAlgoSupportingSubmeshes[ aShapeDim ].push_front( shDim2smIt->second );
559             shDim2sm.clear();
560           }
561           // add smToCompute to shDim2sm map
562           if ( algoShape.IsSame( aMesh.GetShapeToMesh() ))
563           {
564             aShapeDim = globalAlgoDim; // to compute last
565           }
566           else
567           {
568             aShapeDim = GetShapeDim( algoShape );
569             if ( algoShape.ShapeType() == TopAbs_COMPOUND )
570             {
571               TopoDS_Iterator it( algoShape );
572               aShapeDim += GetShapeDim( it.Value() );
573             }
574           }
575           shDim2sm.insert( make_pair( aShapeDim, smToCompute ));
576         }
577         else // Compute w/o support of sub-meshes
578         {
579           if (_compute_canceled)
580             return false;
581           smToCompute->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
582           setCurrentSubMesh( smToCompute );
583           smToCompute->ComputeStateEngine( computeEvent );
584           setCurrentSubMesh( nullptr );
585           smToCompute->SetAllowedSubShapes( nullptr );
586           if ( aShapesId )
587             aShapesId->insert( smToCompute->GetId() );
588         }
589       }
590     }
591     // reload sub-meshes from shDim2sm into smWithAlgoSupportingSubmeshes
592     for ( shDim2smIt = shDim2sm.rbegin(); shDim2smIt != shDim2sm.rend(); ++shDim2smIt )
593       if ( shDim2smIt->first == globalAlgoDim )
594         smWithAlgoSupportingSubmeshes[3].push_back( shDim2smIt->second );
595       else
596         smWithAlgoSupportingSubmeshes[0].push_front( shDim2smIt->second );
597
598     // ======================================================
599     // Apply all-dimensional algorithms supporing sub-meshes
600     // ======================================================
601
602     std::vector< SMESH_subMesh* > smVec;
603     for ( aShapeDim = 0; aShapeDim < 4; ++aShapeDim )
604       smVec.insert( smVec.end(),
605                     smWithAlgoSupportingSubmeshes[aShapeDim].begin(),
606                     smWithAlgoSupportingSubmeshes[aShapeDim].end() );
607
608     // gather sub-shapes with local uni-dimensional algos (bos #29143)
609     // ----------------------------------------------------------------
610     TopTools_MapOfShape uniDimAlgoShapes;
611     if ( !smVec.empty() )
612     {
613       ShapeToHypothesis::Iterator s2hyps( aMesh.GetMeshDS()->GetHypotheses() );
614       for ( ; s2hyps.More(); s2hyps.Next() )
615       {
616         const TopoDS_Shape& s = s2hyps.Key();
617         if ( s.IsSame( aMesh.GetShapeToMesh() ))
618           continue;
619         for ( auto & hyp : s2hyps.Value() )
620         {
621           if ( const SMESH_Algo* algo = dynamic_cast< const SMESH_Algo*>( hyp ))
622             if ( algo->NeedDiscreteBoundary() )
623             {
624               TopAbs_ShapeEnum sType;
625               switch ( algo->GetDim() ) {
626               case 3:  sType = TopAbs_SOLID; break;
627               case 2:  sType = TopAbs_FACE; break;
628               default: sType = TopAbs_EDGE; break;
629               }
630               for ( TopExp_Explorer ex( s2hyps.Key(), sType ); ex.More(); ex.Next() )
631                 uniDimAlgoShapes.Add( ex.Current() );
632             }
633         }
634       }
635     }
636
637     {
638       // ------------------------------------------------
639       // sort list of sub-meshes according to mesh order
640       // ------------------------------------------------
641       aMesh.SortByMeshOrder( smVec );
642
643       // ------------------------------------------------------------
644       // compute sub-meshes with local uni-dimensional algos under
645       // sub-meshes with all-dimensional algos
646       // ------------------------------------------------------------
647       // start from lower shapes
648       for ( size_t i = 0; i < smVec.size(); ++i )
649       {
650         sm = smVec[i];
651         if ( sm->GetComputeState() != SMESH_subMesh::READY_TO_COMPUTE)
652           continue;
653
654         const TopAbs_ShapeEnum shapeType = sm->GetSubShape().ShapeType();
655
656         if ( !uniDimAlgoShapes.IsEmpty() )
657         {
658           // get a shape the algo is assigned to
659           if ( !GetAlgo( sm, & algoShape ))
660             continue; // strange...
661
662           // look for more local algos
663           if ( SMESH_subMesh* algoSM = aMesh.GetSubMesh( algoShape ))
664             smIt = algoSM->getDependsOnIterator(!includeSelf, !complexShapeFirst);
665           else
666             smIt = sm->getDependsOnIterator(!includeSelf, !complexShapeFirst);
667
668           while ( smIt->more() )
669           {
670             SMESH_subMesh* smToCompute = smIt->next();
671
672             const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
673             const           int aShapeDim = GetShapeDim( aSubShape );
674             if ( aShapeDim < 1 || aSubShape.ShapeType() <= shapeType )
675               continue;
676             if ( !uniDimAlgoShapes.Contains( aSubShape ))
677               continue; // [bos #29143] aMesh.GetHypothesis() is too long
678
679             // check for preview dimension limitations
680             if ( aShapesId && GetShapeDim( aSubShape.ShapeType() ) > (int)aDim )
681               continue;
682
683             SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
684             filter
685               .And( SMESH_HypoFilter::IsApplicableTo( aSubShape ))
686               .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape, aMesh ));
687
688             if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( smToCompute, filter, true))
689             {
690               if ( ! subAlgo->NeedDiscreteBoundary() ) continue;
691               TopTools_IndexedMapOfShape* localAllowed = allowedSubShapes;
692               if ( localAllowed && localAllowed->IsEmpty() )
693                 localAllowed = 0; // prevent fillAllowed() with  aSubShape
694
695               SMESH_Hypothesis::Hypothesis_Status status;
696               if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status ))
697                 // mesh a lower smToCompute starting from vertices
698                 Compute( aMesh, aSubShape, aFlags | SHAPE_ONLY_UPWARD, aDim, aShapesId, localAllowed );
699             }
700           }
701         }
702         // --------------------------------
703         // apply the all-dimensional algo
704         // --------------------------------
705         {
706           if (_compute_canceled)
707             return false;
708           // check for preview dimension limitations
709           if ( aShapesId && GetShapeDim( shapeType ) > (int)aDim )
710             continue;
711           sm->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
712
713           setCurrentSubMesh( sm );
714           sm->ComputeStateEngine( computeEvent );
715
716           setCurrentSubMesh( NULL );
717           sm->SetAllowedSubShapes( nullptr );
718           if ( aShapesId )
719             aShapesId->insert( sm->GetId() );
720         }
721       }
722     }
723
724     // -----------------------------------------------
725     // mesh the rest sub-shapes starting from vertices
726     // -----------------------------------------------
727     ret = Compute( aMesh, aShape, aFlags | UPWARD, aDim, aShapesId, allowedSubShapes );
728
729   }
730
731   MEMOSTAT;
732
733   // fix quadratic mesh by bending iternal links near concave boundary
734   if ( aCompactMesh && // a final compute
735        aShape.IsSame( aMesh.GetShapeToMesh() ) &&
736        !aShapesId && // not preview
737        ret ) // everything is OK
738   {
739     SMESH_MesherHelper aHelper( aMesh );
740     if ( aHelper.IsQuadraticMesh() != SMESH_MesherHelper::LINEAR )
741     {
742       aHelper.FixQuadraticElements( shapeSM->GetComputeError() );
743     }
744   }
745
746   if ( aCompactMesh )
747   {
748     aMesh.GetMeshDS()->Modified();
749     aMesh.GetMeshDS()->CompactMesh();
750   }
751   return ret;
752 }
753
754 //=============================================================================
755 /*!
756  * Prepare Compute a mesh
757  */
758 //=============================================================================
759 void SMESH_Gen::PrepareCompute(SMESH_Mesh &          /*aMesh*/,
760                                const TopoDS_Shape &  /*aShape*/)
761 {
762   _compute_canceled = false;
763   resetCurrentSubMesh();
764 }
765
766 //=============================================================================
767 /*!
768  * Cancel Compute a mesh
769  */
770 //=============================================================================
771 void SMESH_Gen::CancelCompute(SMESH_Mesh &          /*aMesh*/,
772                               const TopoDS_Shape &  /*aShape*/)
773 {
774   _compute_canceled = true;
775   if ( const SMESH_subMesh* sm = GetCurrentSubMesh() )
776   {
777     const_cast< SMESH_subMesh* >( sm )->ComputeStateEngine( SMESH_subMesh::COMPUTE_CANCELED );
778   }
779   resetCurrentSubMesh();
780 }
781
782 //================================================================================
783 /*!
784  * \brief Returns a sub-mesh being currently computed
785  */
786 //================================================================================
787
788 const SMESH_subMesh* SMESH_Gen::GetCurrentSubMesh() const
789 {
790   return _sm_current.empty() ? 0 : _sm_current.back();
791 }
792
793 //================================================================================
794 /*!
795  * \brief Sets a sub-mesh being currently computed.
796  *
797  * An algorithm can call Compute() for a sub-shape, hence we keep a stack of sub-meshes
798  */
799 //================================================================================
800
801 void SMESH_Gen::setCurrentSubMesh(SMESH_subMesh* sm)
802 {
803   if ( sm )
804     _sm_current.push_back( sm );
805
806   else if ( !_sm_current.empty() )
807     _sm_current.pop_back();
808 }
809
810 void SMESH_Gen::resetCurrentSubMesh()
811 {
812   _sm_current.clear();
813 }
814
815 //=============================================================================
816 /*!
817  * Evaluate a mesh
818  */
819 //=============================================================================
820
821 bool SMESH_Gen::Evaluate(SMESH_Mesh &          aMesh,
822                          const TopoDS_Shape &  aShape,
823                          MapShapeNbElems&      aResMap,
824                          const bool            anUpward,
825                          TSetOfInt*            aShapesId)
826 {
827   bool ret = true;
828
829   SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
830
831   const bool includeSelf = true;
832   const bool complexShapeFirst = true;
833   SMESH_subMeshIteratorPtr smIt;
834
835   if ( anUpward ) { // is called from below code here
836     // -----------------------------------------------
837     // mesh all the sub-shapes starting from vertices
838     // -----------------------------------------------
839     smIt = sm->getDependsOnIterator(includeSelf, !complexShapeFirst);
840     while ( smIt->more() ) {
841       SMESH_subMesh* smToCompute = smIt->next();
842
843       // do not mesh vertices of a pseudo shape
844       const TopAbs_ShapeEnum shapeType = smToCompute->GetSubShape().ShapeType();
845       //if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX )
846       //  continue;
847       if ( !aMesh.HasShapeToMesh() ) {
848         if( shapeType == TopAbs_VERTEX || shapeType == TopAbs_WIRE ||
849             shapeType == TopAbs_SHELL )
850           continue;
851       }
852
853       smToCompute->Evaluate(aResMap);
854       if( aShapesId )
855         aShapesId->insert( smToCompute->GetId() );
856     }
857     return ret;
858   }
859   else {
860     // -----------------------------------------------------------------
861     // apply algos that DO NOT require Discreteized boundaries and DO NOT
862     // support sub-meshes, starting from the most complex shapes
863     // and collect sub-meshes with algos that DO support sub-meshes
864     // -----------------------------------------------------------------
865     list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes;
866     smIt = sm->getDependsOnIterator(includeSelf, complexShapeFirst);
867     while ( smIt->more() ) {
868       SMESH_subMesh* smToCompute = smIt->next();
869       const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
870       const int aShapeDim = GetShapeDim( aSubShape );
871       if ( aShapeDim < 1 ) break;
872
873       SMESH_Algo* algo = GetAlgo( smToCompute );
874       if ( algo && !algo->NeedDiscreteBoundary() ) {
875         if ( algo->SupportSubmeshes() ) {
876           smWithAlgoSupportingSubmeshes.push_front( smToCompute );
877         }
878         else {
879           smToCompute->Evaluate(aResMap);
880           if ( aShapesId )
881             aShapesId->insert( smToCompute->GetId() );
882         }
883       }
884     }
885
886     // ------------------------------------------------------------
887     // sort list of meshes according to mesh order
888     // ------------------------------------------------------------
889     std::vector< SMESH_subMesh* > smVec( smWithAlgoSupportingSubmeshes.begin(),
890                                          smWithAlgoSupportingSubmeshes.end() );
891     aMesh.SortByMeshOrder( smVec );
892
893     // ------------------------------------------------------------
894     // compute sub-meshes under shapes with algos that DO NOT require
895     // Discreteized boundaries and DO support sub-meshes
896     // ------------------------------------------------------------
897     // start from lower shapes
898     for ( size_t i = 0; i < smVec.size(); ++i )
899     {
900       sm = smVec[i];
901
902       // get a shape the algo is assigned to
903       TopoDS_Shape algoShape;
904       if ( !GetAlgo( sm, & algoShape ))
905         continue; // strange...
906
907       // look for more local algos
908       smIt = sm->getDependsOnIterator(!includeSelf, !complexShapeFirst);
909       while ( smIt->more() ) {
910         SMESH_subMesh* smToCompute = smIt->next();
911
912         const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
913         const int aShapeDim = GetShapeDim( aSubShape );
914         if ( aShapeDim < 1 ) continue;
915
916         SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
917         filter
918           .And( SMESH_HypoFilter::IsApplicableTo( aSubShape ))
919           .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape, aMesh ));
920
921         if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( smToCompute, filter, true ))
922         {
923           if ( ! subAlgo->NeedDiscreteBoundary() ) continue;
924           SMESH_Hypothesis::Hypothesis_Status status;
925           if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status ))
926             // mesh a lower smToCompute starting from vertices
927             Evaluate( aMesh, aSubShape, aResMap, /*anUpward=*/true, aShapesId );
928         }
929       }
930     }
931     // ----------------------------------------------------------
932     // apply the algos that do not require Discreteized boundaries
933     // ----------------------------------------------------------
934     for ( size_t i = 0; i < smVec.size(); ++i )
935     {
936       sm = smVec[i];
937       sm->Evaluate(aResMap);
938       if ( aShapesId )
939         aShapesId->insert( sm->GetId() );
940     }
941
942     // -----------------------------------------------
943     // mesh the rest sub-shapes starting from vertices
944     // -----------------------------------------------
945     ret = Evaluate( aMesh, aShape, aResMap, /*anUpward=*/true, aShapesId );
946   }
947
948   return ret;
949 }
950
951
952 //=======================================================================
953 //function : checkConformIgnoredAlgos
954 //purpose  :
955 //=======================================================================
956
957 static bool checkConformIgnoredAlgos(SMESH_Mesh&               aMesh,
958                                      SMESH_subMesh*            aSubMesh,
959                                      const SMESH_Algo*         aGlobIgnoAlgo,
960                                      const SMESH_Algo*         aLocIgnoAlgo,
961                                      bool &                    checkConform,
962                                      set<SMESH_subMesh*>&      aCheckedMap,
963                                      list< SMESH_Gen::TAlgoStateError > & theErrors)
964 {
965   ASSERT( aSubMesh );
966   if ( aSubMesh->GetSubShape().ShapeType() == TopAbs_VERTEX)
967     return true;
968
969
970   bool ret = true;
971
972   const list<const SMESHDS_Hypothesis*>& listHyp =
973     aMesh.GetMeshDS()->GetHypothesis( aSubMesh->GetSubShape() );
974   list<const SMESHDS_Hypothesis*>::const_iterator it=listHyp.begin();
975   for ( ; it != listHyp.end(); it++)
976   {
977     const SMESHDS_Hypothesis * aHyp = *it;
978     if (aHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO)
979       continue;
980
981     const SMESH_Algo* algo = dynamic_cast<const SMESH_Algo*> (aHyp);
982     ASSERT ( algo );
983
984     if ( aLocIgnoAlgo ) // algo is hidden by a local algo of upper dim
985     {
986       theErrors.push_back( SMESH_Gen::TAlgoStateError() );
987       theErrors.back().Set( SMESH_Hypothesis::HYP_HIDDEN_ALGO, algo, false );
988       INFOS( "Local <" << algo->GetName() << "> is hidden by local <"
989             << aLocIgnoAlgo->GetName() << ">");
990     }
991     else
992     {
993       bool       isGlobal = (aMesh.IsMainShape( aSubMesh->GetSubShape() ));
994       int             dim = algo->GetDim();
995       int aMaxGlobIgnoDim = ( aGlobIgnoAlgo ? aGlobIgnoAlgo->GetDim() : -1 );
996       bool    isNeededDim = ( aGlobIgnoAlgo ? aGlobIgnoAlgo->NeedLowerHyps( dim ) : false );
997
998       if (( dim < aMaxGlobIgnoDim && !isNeededDim ) &&
999           ( isGlobal || !aGlobIgnoAlgo->SupportSubmeshes() ))
1000       {
1001         // algo is hidden by a global algo
1002         theErrors.push_back( SMESH_Gen::TAlgoStateError() );
1003         theErrors.back().Set( SMESH_Hypothesis::HYP_HIDDEN_ALGO, algo, true );
1004         INFOS( ( isGlobal ? "Global" : "Local" )
1005               << " <" << algo->GetName() << "> is hidden by global <"
1006               << aGlobIgnoAlgo->GetName() << ">");
1007       }
1008       else if ( !algo->NeedDiscreteBoundary() && !isGlobal)
1009       {
1010         // local algo is not hidden and hides algos on sub-shapes
1011         if (checkConform && !aSubMesh->IsConform( algo ))
1012         {
1013           ret = false;
1014           checkConform = false; // no more check conformity
1015           INFOS( "ERROR: Local <" << algo->GetName() <<
1016                 "> would produce not conform mesh: "
1017                 "<Not Conform Mesh Allowed> hypothesis is missing");
1018           theErrors.push_back( SMESH_Gen::TAlgoStateError() );
1019           theErrors.back().Set( SMESH_Hypothesis::HYP_NOTCONFORM, algo, false );
1020         }
1021
1022         // sub-algos will be hidden by a local <algo> if <algo> does not support sub-meshes
1023         if ( algo->SupportSubmeshes() )
1024           algo = 0;
1025         SMESH_subMeshIteratorPtr revItSub =
1026           aSubMesh->getDependsOnIterator( /*includeSelf=*/false, /*complexShapeFirst=*/true);
1027         bool checkConform2 = false;
1028         while ( revItSub->more() )
1029         {
1030           SMESH_subMesh* sm = revItSub->next();
1031           checkConformIgnoredAlgos (aMesh, sm, aGlobIgnoAlgo,
1032                                     algo, checkConform2, aCheckedMap, theErrors);
1033           aCheckedMap.insert( sm );
1034         }
1035       }
1036     }
1037   }
1038
1039   return ret;
1040 }
1041
1042 //=======================================================================
1043 //function : checkMissing
1044 //purpose  : notify on missing hypothesis
1045 //           Return false if algo or hipothesis is missing
1046 //=======================================================================
1047
1048 static bool checkMissing(SMESH_Gen*                aGen,
1049                          SMESH_Mesh&               aMesh,
1050                          SMESH_subMesh*            aSubMesh,
1051                          const int                 aTopAlgoDim,
1052                          bool*                     globalChecked,
1053                          const bool                checkNoAlgo,
1054                          set<SMESH_subMesh*>&      aCheckedMap,
1055                          list< SMESH_Gen::TAlgoStateError > & theErrors)
1056 {
1057   switch ( aSubMesh->GetSubShape().ShapeType() )
1058   {
1059   case TopAbs_EDGE:
1060   case TopAbs_FACE:
1061   case TopAbs_SOLID: break; // check this sub-mesh, it can be meshed
1062   default:
1063     return true; // not meshable sub-mesh
1064   }
1065   if ( aCheckedMap.count( aSubMesh ))
1066     return true;
1067
1068   int ret = true;
1069   SMESH_Algo* algo = 0;
1070
1071   switch (aSubMesh->GetAlgoState())
1072   {
1073   case SMESH_subMesh::NO_ALGO: {
1074     if (checkNoAlgo)
1075     {
1076       // should there be any algo?
1077       int shapeDim = SMESH_Gen::GetShapeDim( aSubMesh->GetSubShape() );
1078       if (aTopAlgoDim > shapeDim)
1079       {
1080         MESSAGE( "ERROR: " << shapeDim << "D algorithm is missing" );
1081         ret = false;
1082         theErrors.push_back( SMESH_Gen::TAlgoStateError() );
1083         theErrors.back().Set( SMESH_Hypothesis::HYP_MISSING, shapeDim, true );
1084       }
1085     }
1086     return ret;
1087   }
1088   case SMESH_subMesh::MISSING_HYP: {
1089     // notify if an algo missing hyp is attached to aSubMesh
1090     algo = aSubMesh->GetAlgo();
1091     ASSERT( algo );
1092     bool IsGlobalHypothesis = aGen->IsGlobalHypothesis( algo, aMesh );
1093     if (!IsGlobalHypothesis || !globalChecked[ algo->GetDim() ])
1094     {
1095       TAlgoStateErrorName errName = SMESH_Hypothesis::HYP_MISSING;
1096       SMESH_Hypothesis::Hypothesis_Status status;
1097       algo->CheckHypothesis( aMesh, aSubMesh->GetSubShape(), status );
1098       if ( status == SMESH_Hypothesis::HYP_BAD_PARAMETER ) {
1099         MESSAGE( "ERROR: hypothesis of " << (IsGlobalHypothesis ? "Global " : "Local ")
1100                  << "<" << algo->GetName() << "> has a bad parameter value");
1101         errName = status;
1102       } else if ( status == SMESH_Hypothesis::HYP_BAD_GEOMETRY ) {
1103         MESSAGE( "ERROR: " << (IsGlobalHypothesis ? "Global " : "Local ")
1104                  << "<" << algo->GetName() << "> assigned to mismatching geometry");
1105         errName = status;
1106       } else {
1107         MESSAGE( "ERROR: " << (IsGlobalHypothesis ? "Global " : "Local ")
1108                  << "<" << algo->GetName() << "> misses some hypothesis");
1109       }
1110       if (IsGlobalHypothesis)
1111         globalChecked[ algo->GetDim() ] = true;
1112       theErrors.push_back( SMESH_Gen::TAlgoStateError() );
1113       theErrors.back().Set( errName, algo, IsGlobalHypothesis );
1114     }
1115     ret = false;
1116     break;
1117   }
1118   case SMESH_subMesh::HYP_OK:
1119     algo = aSubMesh->GetAlgo();
1120     ret = true;
1121     if (!algo->NeedDiscreteBoundary())
1122     {
1123       SMESH_subMeshIteratorPtr itsub = aSubMesh->getDependsOnIterator( /*includeSelf=*/false,
1124                                                                        /*complexShapeFirst=*/false);
1125       while ( itsub->more() )
1126         aCheckedMap.insert( itsub->next() );
1127     }
1128     break;
1129   default: ASSERT(0);
1130   }
1131
1132   // do not check under algo that hides sub-algos or
1133   // re-start checking NO_ALGO state
1134   ASSERT (algo);
1135   bool isTopLocalAlgo =
1136     ( aTopAlgoDim <= algo->GetDim() && !aGen->IsGlobalHypothesis( algo, aMesh ));
1137   if (!algo->NeedDiscreteBoundary() || isTopLocalAlgo)
1138   {
1139     bool checkNoAlgo2 = ( algo->NeedDiscreteBoundary() );
1140     SMESH_subMeshIteratorPtr itsub = aSubMesh->getDependsOnIterator( /*includeSelf=*/false,
1141                                                                      /*complexShapeFirst=*/true);
1142     while ( itsub->more() )
1143     {
1144       // sub-meshes should not be checked further more
1145       SMESH_subMesh* sm = itsub->next();
1146
1147       if (isTopLocalAlgo)
1148       {
1149         //check algo on sub-meshes
1150         int aTopAlgoDim2 = algo->GetDim();
1151         if (!checkMissing (aGen, aMesh, sm, aTopAlgoDim2,
1152                            globalChecked, checkNoAlgo2, aCheckedMap, theErrors))
1153         {
1154           ret = false;
1155           if (sm->GetAlgoState() == SMESH_subMesh::NO_ALGO )
1156             checkNoAlgo2 = false;
1157         }
1158       }
1159       aCheckedMap.insert( sm );
1160     }
1161   }
1162   return ret;
1163 }
1164
1165 //=======================================================================
1166 //function : CheckAlgoState
1167 //purpose  : notify on bad state of attached algos, return false
1168 //           if Compute() would fail because of some algo bad state
1169 //=======================================================================
1170
1171 bool SMESH_Gen::CheckAlgoState(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
1172 {
1173   list< TAlgoStateError > errors;
1174   return GetAlgoState( aMesh, aShape, errors );
1175 }
1176
1177 //=======================================================================
1178 //function : GetAlgoState
1179 //purpose  : notify on bad state of attached algos, return false
1180 //           if Compute() would fail because of some algo bad state
1181 //           theErrors list contains problems description
1182 //=======================================================================
1183
1184 bool SMESH_Gen::GetAlgoState(SMESH_Mesh&               theMesh,
1185                              const TopoDS_Shape&       theShape,
1186                              list< TAlgoStateError > & theErrors)
1187 {
1188   bool ret = true;
1189   bool hasAlgo = false;
1190
1191   SMESH_subMesh*          sm = theMesh.GetSubMesh(theShape);
1192   const SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
1193   TopoDS_Shape     mainShape = meshDS->ShapeToMesh();
1194
1195   // -----------------
1196   // get global algos
1197   // -----------------
1198
1199   const SMESH_Algo* aGlobAlgoArr[] = {0,0,0,0};
1200
1201   const list<const SMESHDS_Hypothesis*>& listHyp = meshDS->GetHypothesis( mainShape );
1202   list<const SMESHDS_Hypothesis*>::const_iterator it=listHyp.begin();
1203   for ( ; it != listHyp.end(); it++)
1204   {
1205     const SMESHDS_Hypothesis * aHyp = *it;
1206     if (aHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO)
1207       continue;
1208
1209     const SMESH_Algo* algo = dynamic_cast<const SMESH_Algo*> (aHyp);
1210     ASSERT ( algo );
1211
1212     int dim = algo->GetDim();
1213     aGlobAlgoArr[ dim ] = algo;
1214
1215     hasAlgo = true;
1216   }
1217
1218   // --------------------------------------------------------
1219   // info on algos that will be ignored because of ones that
1220   // don't NeedDiscreteBoundary() attached to super-shapes,
1221   // check that a conform mesh will be produced
1222   // --------------------------------------------------------
1223
1224
1225   // find a global algo possibly hiding sub-algos
1226   int dim;
1227   const SMESH_Algo* aGlobIgnoAlgo = 0;
1228   for (dim = 3; dim > 0; dim--)
1229   {
1230     if (aGlobAlgoArr[ dim ] &&
1231         !aGlobAlgoArr[ dim ]->NeedDiscreteBoundary() /*&&
1232         !aGlobAlgoArr[ dim ]->SupportSubmeshes()*/ )
1233     {
1234       aGlobIgnoAlgo = aGlobAlgoArr[ dim ];
1235       break;
1236     }
1237   }
1238
1239   set<SMESH_subMesh*> aCheckedSubs;
1240   bool checkConform = ( !theMesh.IsNotConformAllowed() );
1241
1242   // loop on theShape and its sub-shapes
1243   SMESH_subMeshIteratorPtr revItSub = sm->getDependsOnIterator( /*includeSelf=*/true,
1244                                                                 /*complexShapeFirst=*/true);
1245   while ( revItSub->more() )
1246   {
1247     SMESH_subMesh* smToCheck = revItSub->next();
1248     if ( smToCheck->GetSubShape().ShapeType() == TopAbs_VERTEX)
1249       break;
1250
1251     if ( aCheckedSubs.insert( smToCheck ).second ) // not yet checked
1252       if (!checkConformIgnoredAlgos (theMesh, smToCheck, aGlobIgnoAlgo,
1253                                      0, checkConform, aCheckedSubs, theErrors))
1254         ret = false;
1255
1256     if ( smToCheck->GetAlgoState() != SMESH_subMesh::NO_ALGO )
1257       hasAlgo = true;
1258   }
1259
1260   // ----------------------------------------------------------------
1261   // info on missing hypothesis and find out if all needed algos are
1262   // well defined
1263   // ----------------------------------------------------------------
1264
1265   // find max dim of global algo
1266   int aTopAlgoDim = 0;
1267   for (dim = 3; dim > 0; dim--)
1268   {
1269     if (aGlobAlgoArr[ dim ])
1270     {
1271       aTopAlgoDim = dim;
1272       break;
1273     }
1274   }
1275   bool checkNoAlgo = theMesh.HasShapeToMesh() ? bool( aTopAlgoDim ) : false;
1276   bool globalChecked[] = { false, false, false, false };
1277
1278   // loop on theShape and its sub-shapes
1279   aCheckedSubs.clear();
1280   revItSub = sm->getDependsOnIterator( /*includeSelf=*/true, /*complexShapeFirst=*/true);
1281   while ( revItSub->more() )
1282   {
1283     SMESH_subMesh* smToCheck = revItSub->next();
1284     if ( smToCheck->GetSubShape().ShapeType() == TopAbs_VERTEX)
1285       break;
1286
1287     if (!checkMissing (this, theMesh, smToCheck, aTopAlgoDim,
1288                        globalChecked, checkNoAlgo, aCheckedSubs, theErrors))
1289     {
1290       ret = false;
1291       if (smToCheck->GetAlgoState() == SMESH_subMesh::NO_ALGO )
1292         checkNoAlgo = false;
1293     }
1294   }
1295
1296   if ( !hasAlgo ) {
1297     ret = false;
1298     theErrors.push_back( TAlgoStateError() );
1299     theErrors.back().Set( SMESH_Hypothesis::HYP_MISSING, theMesh.HasShapeToMesh() ? 1 : 3, true );
1300   }
1301
1302   return ret;
1303 }
1304
1305 //=======================================================================
1306 //function : IsGlobalHypothesis
1307 //purpose  : check if theAlgo is attached to the main shape
1308 //=======================================================================
1309
1310 bool SMESH_Gen::IsGlobalHypothesis(const SMESH_Hypothesis* theHyp, SMESH_Mesh& aMesh)
1311 {
1312   SMESH_HypoFilter filter( SMESH_HypoFilter::Is( theHyp ));
1313   return aMesh.GetHypothesis( aMesh.GetMeshDS()->ShapeToMesh(), filter, false );
1314 }
1315
1316 //================================================================================
1317 /*!
1318  * \brief Return paths to xml files of plugins
1319  */
1320 //================================================================================
1321
1322 std::vector< std::string > SMESH_Gen::GetPluginXMLPaths()
1323 {
1324   // Get paths to xml files of plugins
1325   vector< string > xmlPaths;
1326   string sep;
1327   if ( const char* meshersList = getenv("SMESH_MeshersList") )
1328   {
1329     string meshers = meshersList, plugin;
1330     string::size_type from = 0, pos;
1331     while ( from < meshers.size() )
1332     {
1333       // cut off plugin name
1334       pos = meshers.find( env_sep, from );
1335       if ( pos != string::npos )
1336         plugin = meshers.substr( from, pos-from );
1337       else
1338         plugin = meshers.substr( from ), pos = meshers.size();
1339       from = pos + 1;
1340
1341       // get PLUGIN_ROOT_DIR path
1342       string rootDirVar, pluginSubDir = plugin;
1343       if ( plugin == "StdMeshers" )
1344         rootDirVar = "SMESH", pluginSubDir = "smesh";
1345       else
1346         for ( pos = 0; pos < plugin.size(); ++pos )
1347           rootDirVar += toupper( plugin[pos] );
1348       rootDirVar += "_ROOT_DIR";
1349
1350       const char* rootDir = getenv( rootDirVar.c_str() );
1351       if ( !rootDir || strlen(rootDir) == 0 )
1352       {
1353         rootDirVar = plugin + "_ROOT_DIR"; // HexoticPLUGIN_ROOT_DIR
1354         rootDir = getenv( rootDirVar.c_str() );
1355         if ( !rootDir || strlen(rootDir) == 0 ) continue;
1356       }
1357
1358       // get a separator from rootDir
1359       for ( int i = strlen( rootDir )-1; i >= 0 && sep.empty(); --i )
1360         if ( rootDir[i] == '/' || rootDir[i] == '\\' )
1361         {
1362           sep = rootDir[i];
1363           break;
1364         }
1365 #ifdef WIN32
1366       if (sep.empty() ) sep = "\\";
1367 #else
1368       if (sep.empty() ) sep = "/";
1369 #endif
1370
1371       // get a path to resource file
1372       string xmlPath = rootDir;
1373       if ( xmlPath[ xmlPath.size()-1 ] != sep[0] )
1374         xmlPath += sep;
1375       xmlPath += "share" + sep + "salome" + sep + "resources" + sep;
1376       for ( pos = 0; pos < pluginSubDir.size(); ++pos )
1377         xmlPath += tolower( pluginSubDir[pos] );
1378       xmlPath += sep + plugin + ".xml";
1379       bool fileOK;
1380 #ifdef WIN32
1381 #  ifdef UNICODE
1382       const wchar_t* path = Kernel_Utils::decode_s(xmlPath);
1383       SMESHUtils::ArrayDeleter<const wchar_t> deleter( path );
1384 #  else
1385       const char* path = xmlPath.c_str();
1386 #  endif
1387       fileOK = (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES);
1388
1389 #else
1390       fileOK = (access(xmlPath.c_str(), F_OK) == 0);
1391 #endif
1392       if ( fileOK )
1393         xmlPaths.push_back( xmlPath );
1394     }
1395   }
1396
1397   return xmlPaths;
1398 }
1399
1400 //=============================================================================
1401 /*!
1402  * Finds algo to mesh a shape. Optionally returns a shape the found algo is bound to
1403  */
1404 //=============================================================================
1405
1406 SMESH_Algo *SMESH_Gen::GetAlgo(SMESH_Mesh &         aMesh,
1407                                const TopoDS_Shape & aShape,
1408                                TopoDS_Shape*        assignedTo)
1409 {
1410   return GetAlgo( aMesh.GetSubMesh( aShape ), assignedTo );
1411 }
1412
1413 //=============================================================================
1414 /*!
1415  * Finds algo to mesh a sub-mesh. Optionally returns a shape the found algo is bound to
1416  */
1417 //=============================================================================
1418
1419 SMESH_Algo *SMESH_Gen::GetAlgo(SMESH_subMesh * aSubMesh,
1420                                TopoDS_Shape*   assignedTo)
1421 {
1422   if ( !aSubMesh ) return 0;
1423
1424   const TopoDS_Shape & aShape = aSubMesh->GetSubShape();
1425   SMESH_Mesh&          aMesh  = *aSubMesh->GetFather();
1426
1427   SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
1428   if ( aMesh.HasShapeToMesh() )
1429     filter.And( filter.IsApplicableTo( aShape ));
1430
1431   typedef SMESH_Algo::Features AlgoData;
1432
1433   TopoDS_Shape assignedToShape;
1434   SMESH_Algo* algo =
1435     (SMESH_Algo*) aMesh.GetHypothesis( aSubMesh, filter, true, &assignedToShape );
1436
1437   if ( algo &&
1438        aShape.ShapeType() == TopAbs_FACE &&
1439        !aShape.IsSame( assignedToShape ) &&
1440        SMESH_MesherHelper::NbAncestors( aShape, aMesh, TopAbs_SOLID ) > 1 )
1441   {
1442     // Issue 0021559. If there is another 2D algo with different types of output
1443     // elements that can be used to mesh aShape, and 3D algos on adjacent SOLIDs
1444     // have different types of input elements, we choose a most appropriate 2D algo.
1445
1446     // try to find a concurrent 2D algo
1447     filter.AndNot( filter.Is( algo ));
1448     TopoDS_Shape assignedToShape2;
1449     SMESH_Algo* algo2 =
1450       (SMESH_Algo*) aMesh.GetHypothesis( aSubMesh, filter, true, &assignedToShape2 );
1451     if ( algo2 &&                                                  // algo found
1452          !assignedToShape2.IsSame( aMesh.GetShapeToMesh() ) &&     // algo is local
1453          ( SMESH_MesherHelper::GetGroupType( assignedToShape2 ) == // algo of the same level
1454            SMESH_MesherHelper::GetGroupType( assignedToShape )) &&
1455          aMesh.IsOrderOK( aMesh.GetSubMesh( assignedToShape2 ),    // no forced order
1456                           aMesh.GetSubMesh( assignedToShape  )))
1457     {
1458       // get algos on the adjacent SOLIDs
1459       filter.Init( filter.IsAlgo() ).And( filter.HasDim( 3 ));
1460       vector< SMESH_Algo* > algos3D;
1461       PShapeIteratorPtr solidIt = SMESH_MesherHelper::GetAncestors( aShape, aMesh,
1462                                                                     TopAbs_SOLID );
1463       while ( const TopoDS_Shape* solid = solidIt->next() )
1464         if ( SMESH_Algo* algo3D = (SMESH_Algo*) aMesh.GetHypothesis( *solid, filter, true ))
1465         {
1466           algos3D.push_back( algo3D );
1467           filter.AndNot( filter.HasName( algo3D->GetName() ));
1468         }
1469       // check compatibility of algos
1470       if ( algos3D.size() > 1 )
1471       {
1472         const AlgoData& algoData    = algo->SMESH_Algo::GetFeatures();
1473         const AlgoData& algoData2   = algo2->SMESH_Algo::GetFeatures();
1474         const AlgoData& algoData3d0 = algos3D[0]->SMESH_Algo::GetFeatures();
1475         const AlgoData& algoData3d1 = algos3D[1]->SMESH_Algo::GetFeatures();
1476         if (( algoData2.IsCompatible( algoData3d0 ) &&
1477               algoData2.IsCompatible( algoData3d1 ))
1478             &&
1479             !(algoData.IsCompatible( algoData3d0 ) &&
1480               algoData.IsCompatible( algoData3d1 )))
1481           algo = algo2;
1482       }
1483     }
1484   }
1485
1486   if ( assignedTo && algo )
1487     * assignedTo = assignedToShape;
1488
1489   return algo;
1490 }
1491
1492 //=============================================================================
1493 /*!
1494  * Returns StudyContextStruct for a study
1495  */
1496 //=============================================================================
1497
1498 StudyContextStruct *SMESH_Gen::GetStudyContext()
1499 {
1500   return _studyContext;
1501 }
1502
1503 //================================================================================
1504 /*!
1505  * \brief Return shape dimension by TopAbs_ShapeEnum
1506  */
1507 //================================================================================
1508
1509 int SMESH_Gen::GetShapeDim(const TopAbs_ShapeEnum & aShapeType)
1510 {
1511   static vector<int> dim;
1512   if ( dim.empty() )
1513   {
1514     dim.resize( TopAbs_SHAPE, -1 );
1515     dim[ TopAbs_COMPOUND ]  = MeshDim_3D;
1516     dim[ TopAbs_COMPSOLID ] = MeshDim_3D;
1517     dim[ TopAbs_SOLID ]     = MeshDim_3D;
1518     dim[ TopAbs_SHELL ]     = MeshDim_2D;
1519     dim[ TopAbs_FACE  ]     = MeshDim_2D;
1520     dim[ TopAbs_WIRE ]      = MeshDim_1D;
1521     dim[ TopAbs_EDGE ]      = MeshDim_1D;
1522     dim[ TopAbs_VERTEX ]    = MeshDim_0D;
1523   }
1524   return dim[ aShapeType ];
1525 }
1526
1527 //================================================================================
1528 /*!
1529  * \brief Return shape dimension by exploding compounds
1530  */
1531 //================================================================================
1532
1533 int SMESH_Gen::GetFlatShapeDim(const TopoDS_Shape &aShape)
1534 {
1535   int aShapeDim;
1536   if ( aShape.ShapeType() == TopAbs_COMPOUND ||
1537        aShape.ShapeType() == TopAbs_COMPSOLID )
1538   {
1539     TopoDS_Iterator it( aShape );
1540     aShapeDim = GetFlatShapeDim( it.Value() );
1541   }
1542   else
1543     aShapeDim = GetShapeDim( aShape );
1544   return aShapeDim;
1545 }
1546
1547 //=============================================================================
1548 /*!
1549  * Generate a new id unique within this Gen
1550  */
1551 //=============================================================================
1552
1553 int SMESH_Gen::GetANewId()
1554 {
1555   return _hypId++;
1556 }