Salome HOME
Remove useless MESSAGEs
[modules/smesh.git] / src / StdMeshers / StdMeshers_ViscousLayers.cxx
index 1a117aff222f58264a7e1d2ff30eb78281070213..5d19beb854cc2243a8120e716d0b39c943e5395f 100644 (file)
@@ -439,6 +439,7 @@ namespace VISCOUS_3D
                   SMOOTHED_C1     = 0x0000800, // is on _eosC1
                   DISTORTED       = 0x0001000, // was bad before smoothing
                   RISKY_SWOL      = 0x0002000, // SWOL is parallel to a source FACE
+                  SHRUNK          = 0x0004000, // target node reached a tgt position while shrink()
                   UNUSED_FLAG     = 0x0100000
     };
     bool Is   ( int flag ) const { return _flags & flag; }
@@ -721,6 +722,7 @@ namespace VISCOUS_3D
   {
     typedef const StdMeshers_ViscousLayers* THyp;
     TopoDS_Shape                    _solid;
+    TopTools_MapOfShape             _before; // SOLIDs to be computed before _solid
     TGeomID                         _index; // SOLID id
     _MeshOfSolid*                   _proxyMesh;
     list< THyp >                    _hyps;
@@ -891,6 +893,7 @@ namespace VISCOUS_3D
   private:
 
     bool findSolidsWithLayers();
+    bool setBefore( _SolidData& solidBefore, _SolidData& solidAfter );
     bool findFacesWithLayers(const bool onlyWith=false);
     void getIgnoreFaces(const TopoDS_Shape&             solid,
                         const StdMeshers_ViscousLayers* hyp,
@@ -957,7 +960,7 @@ namespace VISCOUS_3D
                         _LayerEdge&   edge,
                         const gp_XYZ& newNormal);
     bool refine(_SolidData& data);
-    bool shrink();
+    bool shrink(_SolidData& data);
     bool prepareEdgeToShrink( _LayerEdge& edge, _EdgesOnShape& eos,
                               SMESH_MesherHelper& helper,
                               const SMESHDS_SubMesh* faceSubMesh );
@@ -967,7 +970,7 @@ namespace VISCOUS_3D
                      const bool                  is2D,
                      const int                   step,
                      set<const SMDS_MeshNode*> * involvedNodes=NULL);
-    bool addBoundaryElements();
+    bool addBoundaryElements(_SolidData& data);
 
     bool error( const string& text, int solidID=-1 );
     SMESHDS_Mesh* getMeshDS() const { return _mesh->GetMeshDS(); }
@@ -975,11 +978,14 @@ namespace VISCOUS_3D
     // debug
     void makeGroupOfLE();
 
-    SMESH_Mesh*           _mesh;
-    SMESH_ComputeErrorPtr _error;
+    SMESH_Mesh*                _mesh;
+    SMESH_ComputeErrorPtr      _error;
 
-    vector< _SolidData >  _sdVec;
-    int                   _tmpFaceID;
+    vector<                    _SolidData >  _sdVec;
+    TopTools_IndexedMapOfShape _solids; // to find _SolidData by a solid
+    TopTools_MapOfShape        _shrinkedFaces;
+
+    int                        _tmpFaceID;
   };
   //--------------------------------------------------------------------------------
   /*!
@@ -1232,8 +1238,8 @@ StdMeshers_ViscousLayers::Compute(SMESH_Mesh&         theMesh,
                                   const bool          toMakeN2NMap) const
 {
   using namespace VISCOUS_3D;
-  _ViscousBuilder bulder;
-  SMESH_ComputeErrorPtr err = bulder.Compute( theMesh, theShape );
+  _ViscousBuilder builder;
+  SMESH_ComputeErrorPtr err = builder.Compute( theMesh, theShape );
   if ( err && !err->IsOK() )
     return SMESH_ProxyMesh::Ptr();
 
@@ -1245,7 +1251,7 @@ StdMeshers_ViscousLayers::Compute(SMESH_Mesh&         theMesh,
          _ViscousListener::GetSolidMesh( &theMesh, exp.Current(), /*toCreate=*/false))
     {
       if ( toMakeN2NMap && !pm->_n2nMapComputed )
-        if ( !bulder.MakeN2NMap( pm ))
+        if ( !builder.MakeN2NMap( pm ))
           return SMESH_ProxyMesh::Ptr();
       components.push_back( SMESH_ProxyMesh::Ptr( pm ));
       pm->myIsDeletable = false; // it will de deleted by boost::shared_ptr
@@ -1309,8 +1315,8 @@ StdMeshers_ViscousLayers::CheckHypothesis(SMESH_Mesh&                          t
                                           const TopoDS_Shape&                  theShape,
                                           SMESH_Hypothesis::Hypothesis_Status& theStatus)
 {
-  VISCOUS_3D::_ViscousBuilder bulder;
-  SMESH_ComputeErrorPtr err = bulder.CheckHypotheses( theMesh, theShape );
+  VISCOUS_3D::_ViscousBuilder builder;
+  SMESH_ComputeErrorPtr err = builder.CheckHypotheses( theMesh, theShape );
   if ( err && !err->IsOK() )
     theStatus = SMESH_Hypothesis::HYP_INCOMPAT_HYPS;
   else
@@ -1834,8 +1840,6 @@ bool _ViscousBuilder::MakeN2NMap( _MeshOfSolid* pm )
 SMESH_ComputeErrorPtr _ViscousBuilder::Compute(SMESH_Mesh&         theMesh,
                                                const TopoDS_Shape& theShape)
 {
-  // TODO: set priority of solids during Gen::Compute()
-
   _mesh = & theMesh;
 
   // check if proxy mesh already computed
@@ -1857,22 +1861,33 @@ SMESH_ComputeErrorPtr _ViscousBuilder::Compute(SMESH_Mesh&         theMesh,
 
   for ( size_t i = 0; i < _sdVec.size(); ++i )
   {
-    if ( ! makeLayer(_sdVec[i]) )
+    size_t iSD = 0;
+    for ( iSD = 0; iSD < _sdVec.size(); ++iSD ) // find next SOLID to compute
+      if ( _sdVec[iSD]._before.IsEmpty() &&
+           _sdVec[iSD]._n2eMap.empty() )
+        break;
+
+    if ( ! makeLayer(_sdVec[iSD]) )   // create _LayerEdge's
       return _error;
 
-    if ( _sdVec[i]._n2eMap.size() == 0 )
+    if ( _sdVec[iSD]._n2eMap.size() == 0 )
       continue;
     
-    if ( ! inflate(_sdVec[i]) )
+    if ( ! inflate(_sdVec[iSD]) )     // increase length of _LayerEdge's
       return _error;
 
-    if ( ! refine(_sdVec[i]) )
+    if ( ! refine(_sdVec[iSD]) )      // create nodes and prisms
       return _error;
-  }
-  if ( !shrink() )
-    return _error;
 
-  addBoundaryElements();
+    if ( ! shrink(_sdVec[iSD]) )      // shrink 2D mesh on FACEs w/o layer
+      return _error;
+
+    addBoundaryElements(_sdVec[iSD]); // create quadrangles on prism bare sides
+
+    const TopoDS_Shape& solid = _sdVec[iSD]._solid;
+    for ( iSD = 0; iSD < _sdVec.size(); ++iSD )
+      _sdVec[iSD]._before.Remove( solid );
+  }
 
   makeGroupOfLE(); // debug
   debugDump.Finish();
@@ -1921,12 +1936,14 @@ bool _ViscousBuilder::findSolidsWithLayers()
   TopExp::MapShapes( _mesh->GetShapeToMesh(), TopAbs_SOLID, allSolids );
   _sdVec.reserve( allSolids.Extent());
 
-  SMESH_Gen* gen = _mesh->GetGen();
   SMESH_HypoFilter filter;
   for ( int i = 1; i <= allSolids.Extent(); ++i )
   {
     // find StdMeshers_ViscousLayers hyp assigned to the i-th solid
-    SMESH_Algo* algo = gen->GetAlgo( *_mesh, allSolids(i) );
+    SMESH_subMesh* sm = _mesh->GetSubMesh( allSolids(i) );
+    if ( sm->GetSubMeshDS() && sm->GetSubMeshDS()->NbElements() > 0 )
+      continue; // solid is already meshed
+    SMESH_Algo* algo = sm->GetAlgo();
     if ( !algo ) continue;
     // TODO: check if algo is hidden
     const list <const SMESHDS_Hypothesis *> & allHyps =
@@ -1951,6 +1968,7 @@ bool _ViscousBuilder::findSolidsWithLayers()
           soData->_index = getMeshDS()->ShapeToIndex( allSolids(i));
           soData->_helper = new SMESH_MesherHelper( *_mesh );
           soData->_helper->SetSubShape( allSolids(i) );
+          _solids.Add( allSolids(i) );
         }
         soData->_hyps.push_back( viscHyp );
         soData->_hypShapes.push_back( hypShape );
@@ -1965,7 +1983,37 @@ bool _ViscousBuilder::findSolidsWithLayers()
 
 //================================================================================
 /*!
- * \brief 
+ * \brief Set a _SolidData to be computed before another
+ */
+//================================================================================
+
+bool _ViscousBuilder::setBefore( _SolidData& solidBefore, _SolidData& solidAfter )
+{
+  // check possibility to set this order; get all solids before solidBefore
+  TopTools_IndexedMapOfShape allSolidsBefore;
+  allSolidsBefore.Add( solidBefore._solid );
+  for ( int i = 1; i <= allSolidsBefore.Extent(); ++i )
+  {
+    int iSD = _solids.FindIndex( allSolidsBefore(i) );
+    if ( iSD )
+    {
+      TopTools_MapIteratorOfMapOfShape soIt( _sdVec[ iSD-1 ]._before );
+      for ( ; soIt.More(); soIt.Next() )
+        allSolidsBefore.Add( soIt.Value() );
+    }
+  }
+  if ( allSolidsBefore.Contains( solidAfter._solid ))
+    return false;
+
+  for ( int i = 1; i <= allSolidsBefore.Extent(); ++i )
+    solidAfter._before.Add( allSolidsBefore(i) );
+
+  return true;
+}
+
+//================================================================================
+/*!
+ * \brief
  */
 //================================================================================
 
@@ -1973,13 +2021,10 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith)
 {
   SMESH_MesherHelper helper( *_mesh );
   TopExp_Explorer exp;
-  TopTools_IndexedMapOfShape solids;
 
   // collect all faces-to-ignore defined by hyp
   for ( size_t i = 0; i < _sdVec.size(); ++i )
   {
-    solids.Add( _sdVec[i]._solid );
-
     // get faces-to-ignore defined by each hyp
     typedef const StdMeshers_ViscousLayers* THyp;
     typedef std::pair< set<TGeomID>, THyp > TFacesOfHyp;
@@ -2077,6 +2122,7 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith)
 
   // Find faces to shrink mesh on (solution 2 in issue 0020832);
   TopTools_IndexedMapOfShape shapes;
+  std::string structAlgoName = "Hexa_3D";
   for ( size_t i = 0; i < _sdVec.size(); ++i )
   {
     shapes.Clear();
@@ -2097,7 +2143,7 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith)
       // check presence of layers on them
       int ignore[2];
       for ( int j = 0; j < 2; ++j )
-        ignore[j] = _sdVec[i]._ignoreFaceIds.count ( getMeshDS()->ShapeToIndex( FF[j] ));
+        ignore[j] = _sdVec[i]._ignoreFaceIds.count( getMeshDS()->ShapeToIndex( FF[j] ));
       if ( ignore[0] == ignore[1] )
         continue; // nothing interesting
       TopoDS_Shape fWOL = FF[ ignore[0] ? 0 : 1 ];
@@ -2107,13 +2153,17 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith)
       while ( const TopoDS_Shape* solid = sIt->next() )
         if ( !solid->IsSame( _sdVec[i]._solid ))
         {
-          int iSolid = solids.FindIndex( *solid );
+          int iSolid = _solids.FindIndex( *solid );
           int  iFace = getMeshDS()->ShapeToIndex( fWOL );
           if ( iSolid > 0 && !_sdVec[ iSolid-1 ]._ignoreFaceIds.count( iFace ))
           {
-            //_sdVec[i]._noShrinkShapes.insert( iFace );
-            //fWOL.Nullify();
-            collision = true;
+            // check if solid's mesh is unstructured and then try to set it
+            // to be computed after the i-th solid
+            SMESH_Algo*  algo = _mesh->GetSubMesh( *solid )->GetAlgo();
+            bool isStructured = ( algo->GetName() == structAlgoName );
+            if ( isStructured || !setBefore( _sdVec[ i ], _sdVec[ iSolid-1 ] ))
+              collision = true; // don't shrink fWOL
+            break;
           }
         }
       // add edge to maps
@@ -2126,13 +2176,15 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith)
           // _shrinkShape2Shape will be used to temporary inflate _LayerEdge's based
           // on the edge but shrink won't be performed
           _sdVec[i]._noShrinkShapes.insert( edgeInd );
+          for ( TopoDS_Iterator vIt( edge ); vIt.More(); vIt.Next() )
+            _sdVec[i]._noShrinkShapes.insert( getMeshDS()->ShapeToIndex( vIt.Value() ));
         }
       }
     }
   }
   // Exclude from _shrinkShape2Shape FACE's that can't be shrinked since
   // the algo of the SOLID sharing the FACE does not support it
-  set< string > notSupportAlgos; notSupportAlgos.insert("Hexa_3D");
+  set< string > notSupportAlgos; notSupportAlgos.insert( structAlgoName );
   for ( size_t i = 0; i < _sdVec.size(); ++i )
   {
     map< TGeomID, TopoDS_Shape >::iterator e2f = _sdVec[i]._shrinkShape2Shape.begin();
@@ -2146,7 +2198,7 @@ bool _ViscousBuilder::findFacesWithLayers(const bool onlyWith)
       {
         const TopoDS_Shape* solid = soIt->next();
         if ( _sdVec[i]._solid.IsSame( *solid )) continue;
-        SMESH_Algo* algo = _mesh->GetGen()->GetAlgo( *_mesh, *solid );
+        SMESH_Algo* algo = _mesh->GetSubMesh( *solid )->GetAlgo();
         if ( !algo || !notSupportAlgos.count( algo->GetName() )) continue;
         notShrinkFace = true;
         size_t iSolid = 0;
@@ -9628,71 +9680,93 @@ bool _ViscousBuilder::refine(_SolidData& data)
  */
 //================================================================================
 
-bool _ViscousBuilder::shrink()
+bool _ViscousBuilder::shrink(_SolidData& theData)
 {
-  // make map of (ids of FACEs to shrink mesh on) to (_SolidData containing _LayerEdge's
-  // inflated along FACE or EDGE)
-  map< TGeomID, _SolidData* > f2sdMap;
+  // make map of (ids of FACEs to shrink mesh on) to (list of _SolidData containing
+  // _LayerEdge's inflated along FACE or EDGE)
+  map< TGeomID, list< _SolidData* > > f2sdMap;
   for ( size_t i = 0 ; i < _sdVec.size(); ++i )
   {
     _SolidData& data = _sdVec[i];
-    TopTools_MapOfShape FFMap;
     map< TGeomID, TopoDS_Shape >::iterator s2s = data._shrinkShape2Shape.begin();
     for (; s2s != data._shrinkShape2Shape.end(); ++s2s )
-      if ( s2s->second.ShapeType() == TopAbs_FACE )
+      if ( s2s->second.ShapeType() == TopAbs_FACE && !_shrinkedFaces.Contains( s2s->second ))
       {
-        f2sdMap.insert( make_pair( getMeshDS()->ShapeToIndex( s2s->second ), &data ));
+        f2sdMap[ getMeshDS()->ShapeToIndex( s2s->second )].push_back( &data );
 
-        if ( FFMap.Add( (*s2s).second ))
-          // Put mesh faces on the shrinked FACE to the proxy sub-mesh to avoid
-          // usage of mesh faces made in addBoundaryElements() by the 3D algo or
-          // by StdMeshers_QuadToTriaAdaptor
-          if ( SMESHDS_SubMesh* smDS = getMeshDS()->MeshElements( s2s->second ))
+        // Put mesh faces on the shrinked FACE to the proxy sub-mesh to avoid
+        // usage of mesh faces made in addBoundaryElements() by the 3D algo or
+        // by StdMeshers_QuadToTriaAdaptor
+        if ( SMESHDS_SubMesh* smDS = getMeshDS()->MeshElements( s2s->second ))
+        {
+          SMESH_ProxyMesh::SubMesh* proxySub =
+            data._proxyMesh->getFaceSubM( TopoDS::Face( s2s->second ), /*create=*/true);
+          if ( proxySub->NbElements() == 0 )
           {
-            SMESH_ProxyMesh::SubMesh* proxySub =
-              data._proxyMesh->getFaceSubM( TopoDS::Face( s2s->second ), /*create=*/true);
             SMDS_ElemIteratorPtr fIt = smDS->GetElements();
             while ( fIt->more() )
-              proxySub->AddElement( fIt->next() );
-            // as a result 3D algo will use elements from proxySub and not from smDS
+            {
+              const SMDS_MeshElement* f = fIt->next();
+              // as a result 3D algo will use elements from proxySub and not from smDS
+              proxySub->AddElement( f );
+              f->setIsMarked( true );
+
+              // Mark nodes on the FACE to discriminate them from nodes
+              // added by addBoundaryElements(); marked nodes are to be smoothed while shrink()
+              for ( int iN = 0, nbN = f->NbNodes(); iN < nbN; ++iN )
+              {
+                const SMDS_MeshNode* n = f->GetNode( iN );
+                if ( n->GetPosition()->GetDim() == 2 )
+                  n->setIsMarked( true );
+              }
+            }
           }
+        }
       }
   }
 
   SMESH_MesherHelper helper( *_mesh );
   helper.ToFixNodeParameters( true );
 
-  // EDGE's to shrink
+  // EDGEs to shrink
   map< TGeomID, _Shrinker1D > e2shrMap;
   vector< _EdgesOnShape* > subEOS;
   vector< _LayerEdge* > lEdges;
 
-  // loop on FACES to srink mesh on
-  map< TGeomID, _SolidData* >::iterator f2sd = f2sdMap.begin();
+  // loop on FACEs to srink mesh on
+  map< TGeomID, list< _SolidData* > >::iterator f2sd = f2sdMap.begin();
   for ( ; f2sd != f2sdMap.end(); ++f2sd )
   {
-    _SolidData&      data = *f2sd->second;
+    list< _SolidData* > & dataList = f2sd->second;
+    if ( dataList.front()->_n2eMap.empty() ||
+         dataList.back() ->_n2eMap.empty() )
+      continue; // not yet computed
+    if ( dataList.front() != &theData &&
+         dataList.back()  != &theData )
+      continue;
+
+    _SolidData&      data = *dataList.front();
     const TopoDS_Face&  F = TopoDS::Face( getMeshDS()->IndexToShape( f2sd->first ));
     SMESH_subMesh*     sm = _mesh->GetSubMesh( F );
     SMESHDS_SubMesh* smDS = sm->GetSubMeshDS();
 
-    Handle(Geom_Surface) surface = BRep_Tool::Surface(F);
+    Handle(Geom_Surface) surface = BRep_Tool::Surface( F );
 
-    helper.SetSubShape(F);
+    _shrinkedFaces.Add( F );
+    helper.SetSubShape( F );
 
     // ===========================
     // Prepare data for shrinking
     // ===========================
 
-    // Collect nodes to smooth, as src nodes are not yet replaced by tgt ones
-    // and hence all nodes on a FACE connected to 2d elements are to be smoothed
+    // Collect nodes to smooth, they are marked at the beginning of this method
     vector < const SMDS_MeshNode* > smoothNodes;
     {
       SMDS_NodeIteratorPtr nIt = smDS->GetNodes();
       while ( nIt->more() )
       {
         const SMDS_MeshNode* n = nIt->next();
-        if ( n->NbInverseElements( SMDSAbs_Face ) > 0 )
+        if ( n->isMarked() )
           smoothNodes.push_back( n );
       }
     }
@@ -9704,10 +9778,10 @@ bool _ViscousBuilder::shrink()
     {
       vector<_Simplex> simplices;
       _Simplex::GetSimplices( smoothNodes[0], simplices, ignoreShapes );
-      helper.GetNodeUV( F, simplices[0]._nPrev, 0, &isOkUV ); // fix UV of silpmex nodes
+      helper.GetNodeUV( F, simplices[0]._nPrev, 0, &isOkUV ); // fix UV of simplex nodes
       helper.GetNodeUV( F, simplices[0]._nNext, 0, &isOkUV );
       gp_XY uv = helper.GetNodeUV( F, smoothNodes[0], 0, &isOkUV );
-      if ( !simplices[0].IsForward(uv, smoothNodes[0], F, helper,refSign) )
+      if ( !simplices[0].IsForward(uv, smoothNodes[0], F, helper, refSign ))
         refSign = -1;
     }
 
@@ -9757,7 +9831,7 @@ bool _ViscousBuilder::shrink()
         while ( fIt->more() )
         {
           const SMDS_MeshElement* f = fIt->next();
-          if ( !smDS->Contains( f ))
+          if ( !smDS->Contains( f ) || !f->isMarked() )
             continue;
           SMDS_NodeIteratorPtr nIt = f->nodeIterator();
           for ( int iN = 0; nIt->more(); ++iN )
@@ -9815,6 +9889,10 @@ bool _ViscousBuilder::shrink()
         {
           _LayerEdge& edge = * eos._edges[i];
           _Simplex::GetSimplices( /*tgtNode=*/edge._nodes.back(), edge._simplices, ignoreShapes );
+
+          // additionally mark tgt node; only marked nodes will be used in SetNewLength2d()
+          // not-marked nodes are those added by refine()
+          edge._nodes.back()->setIsMarked( true );
         }
       }
     }
@@ -9951,6 +10029,8 @@ bool _ViscousBuilder::shrink()
 
     if ( !errMsg.empty() ) // Try to re-compute the shrink FACE
     {
+      debugMsg( "Re-compute FACE " << f2sd->first << " because " << errMsg );
+
       // remove faces
       SMESHDS_SubMesh* psm = data._proxyMesh->getFaceSubM( F );
       {
@@ -9990,7 +10070,8 @@ bool _ViscousBuilder::shrink()
         {
           _LayerEdge*       edge = subEOS[iS]->_edges[i];
           SMDS_MeshNode* tgtNode = const_cast< SMDS_MeshNode*& >( edge->_nodes.back() );
-          if ( edge->_pos.empty() ) continue;
+          if ( edge->_pos.empty() ||
+               edge->Is( _LayerEdge::SHRUNK )) continue;
           if ( subEOS[iS]->SWOLType() == TopAbs_FACE )
           {
             SMDS_FacePosition* pos = static_cast<SMDS_FacePosition*>( tgtNode->GetPosition() );
@@ -10178,6 +10259,7 @@ bool _ViscousBuilder::prepareEdgeToShrink( _LayerEdge&            edge,
     if ( tgtNode->GetPosition()->GetDim() != 2 ) // not inflated edge
     {
       edge._pos.clear();
+      edge.Set( _LayerEdge::SHRUNK );
       return srcNode == tgtNode;
     }
     gp_XY srcUV ( edge._pos[0].X(), edge._pos[0].Y() );          //helper.GetNodeUV( F, srcNode );
@@ -10188,7 +10270,7 @@ bool _ViscousBuilder::prepareEdgeToShrink( _LayerEdge&            edge,
     edge._normal.SetCoord( uvDir.X(),uvDir.Y(), 0 );
     edge._len = uvLen;
 
-    edge._pos.resize(1);
+    //edge._pos.resize(1);
     edge._pos[0].SetCoord( tgtUV.X(), tgtUV.Y(), 0 );
 
     // set UV of source node to target node
@@ -10201,6 +10283,7 @@ bool _ViscousBuilder::prepareEdgeToShrink( _LayerEdge&            edge,
     if ( tgtNode->GetPosition()->GetDim() != 1 ) // not inflated edge
     {
       edge._pos.clear();
+      edge.Set( _LayerEdge::SHRUNK );
       return srcNode == tgtNode;
     }
     const TopoDS_Edge&    E = TopoDS::Edge( eos._sWOL );
@@ -10224,14 +10307,15 @@ bool _ViscousBuilder::prepareEdgeToShrink( _LayerEdge&            edge,
     double uTgt = helper.GetNodeU( E, tgtNode, srcNode );
     double u2   = helper.GetNodeU( E, n2, srcNode );
 
-    edge._pos.clear();
+    //edge._pos.clear();
 
     if ( fabs( uSrc-uTgt ) < 0.99 * fabs( uSrc-u2 ))
     {
       // tgtNode is located so that it does not make faces with wrong orientation
+      edge.Set( _LayerEdge::SHRUNK );
       return true;
     }
-    edge._pos.resize(1);
+    //edge._pos.resize(1);
     edge._pos[0].SetCoord( U_TGT, uTgt );
     edge._pos[0].SetCoord( U_SRC, uSrc );
     edge._pos[0].SetCoord( LEN_TGT, fabs( uSrc-uTgt ));
@@ -10452,7 +10536,7 @@ bool _LayerEdge::SetNewLength2d( Handle(Geom_Surface)& surface,
                                  _EdgesOnShape&        eos,
                                  SMESH_MesherHelper&   helper )
 {
-  if ( _pos.empty() )
+  if ( Is( SHRUNK ))
     return false; // already at the target position
 
   SMDS_MeshNode* tgtNode = const_cast< SMDS_MeshNode*& >( _nodes.back() );
@@ -10469,6 +10553,10 @@ bool _LayerEdge::SetNewLength2d( Handle(Geom_Surface)& surface,
     double stepSize = 1e100;
     for ( size_t i = 0; i < _simplices.size(); ++i )
     {
+      if ( !_simplices[i]._nPrev->isMarked() ||
+           !_simplices[i]._nNext->isMarked() )
+        continue; // simplex of quadrangle created by addBoundaryElements()
+
       // find intersection of 2 lines: curUV-tgtUV and that connecting simplex nodes
       gp_XY uvN1 = helper.GetNodeUV( F, _simplices[i]._nPrev );
       gp_XY uvN2 = helper.GetNodeUV( F, _simplices[i]._nNext );
@@ -10484,7 +10572,8 @@ bool _LayerEdge::SetNewLength2d( Handle(Geom_Surface)& surface,
     if ( uvLen <= stepSize )
     {
       newUV = tgtUV;
-      _pos.clear();
+      Set( SHRUNK );
+      //_pos.clear();
     }
     else if ( stepSize > 0 )
     {
@@ -10517,7 +10606,8 @@ bool _LayerEdge::SetNewLength2d( Handle(Geom_Surface)& surface,
     double newU = _pos[0].Coord( U_TGT );
     if ( lenTgt < 0.99 * fabs( uSrc-u2 )) // n2 got out of src-tgt range
     {
-      _pos.clear();
+      Set( _LayerEdge::SHRUNK );
+      //_pos.clear();
     }
     else
     {
@@ -10787,9 +10877,18 @@ void _Shrinker1D::AddEdge( const _LayerEdge*   e,
     while ( nIt->more() )
     {
       const SMDS_MeshNode* node = nIt->next();
+
+      // skip refinement nodes
       if ( node->NbInverseElements(SMDSAbs_Edge) == 0 ||
            node == tgtNode0 || node == tgtNode1 )
-        continue; // refinement nodes
+        continue;
+      bool hasMarkedFace = false;
+      SMDS_ElemIteratorPtr fIt = node->GetInverseElementIterator(SMDSAbs_Face);
+      while ( fIt->more() && !hasMarkedFace )
+        hasMarkedFace = fIt->next()->isMarked();
+      if ( !hasMarkedFace )
+        continue;
+
       _nodes.push_back( node );
       _initU.push_back( helper.GetNodeU( _geomEdge, node ));
       double len = GCPnts_AbscissaPoint::Length(aCurve, f, _initU.back());
@@ -10822,8 +10921,8 @@ void _Shrinker1D::Compute(bool set3D, SMESH_MesherHelper& helper)
   if ( !e ) e = _edges[1];
   if ( !e ) return;
 
-  _done =  (( !_edges[0] || _edges[0]->_pos.empty() ) &&
-            ( !_edges[1] || _edges[1]->_pos.empty() ));
+  _done =  (( !_edges[0] || _edges[0]->Is( _LayerEdge::SHRUNK )) &&
+            ( !_edges[1] || _edges[1]->Is( _LayerEdge::SHRUNK )));
 
   double f,l;
   if ( set3D || _done )
@@ -10904,11 +11003,12 @@ void _Shrinker1D::SwapSrcTgtNodes( SMESHDS_Mesh* mesh )
     if ( !eSubMesh ) return;
     const SMDS_MeshNode* srcNode = _edges[i]->_nodes[0];
     const SMDS_MeshNode* tgtNode = _edges[i]->_nodes.back();
+    const SMDS_MeshNode* scdNode = _edges[i]->_nodes[1];
     SMDS_ElemIteratorPtr eIt = srcNode->GetInverseElementIterator(SMDSAbs_Edge);
     while ( eIt->more() )
     {
       const SMDS_MeshElement* e = eIt->next();
-      if ( !eSubMesh->Contains( e ))
+      if ( !eSubMesh->Contains( e ) || e->GetNodeIndex( scdNode ) >= 0 )
           continue;
       SMDS_ElemIteratorPtr nIt = e->nodesIterator();
       for ( int iN = 0; iN < e->NbNodes(); ++iN )
@@ -10927,15 +11027,15 @@ void _Shrinker1D::SwapSrcTgtNodes( SMESHDS_Mesh* mesh )
  */
 //================================================================================
 
-bool _ViscousBuilder::addBoundaryElements()
+bool _ViscousBuilder::addBoundaryElements(_SolidData& data)
 {
   SMESH_MesherHelper helper( *_mesh );
 
   vector< const SMDS_MeshNode* > faceNodes;
 
-  for ( size_t i = 0; i < _sdVec.size(); ++i )
+  //for ( size_t i = 0; i < _sdVec.size(); ++i )
   {
-    _SolidData& data = _sdVec[i];
+    //_SolidData& data = _sdVec[i];
     TopTools_IndexedMapOfShape geomEdges;
     TopExp::MapShapes( data._solid, TopAbs_EDGE, geomEdges );
     for ( int iE = 1; iE <= geomEdges.Extent(); ++iE )