]> SALOME platform Git repositories - tools/medcoupling.git/commitdiff
Salome HOME
buildInnerBoundaryAlongM1Group(): bug fix for triangular/tetra mesh.
authorabn <adrien.bruneton@cea.fr>
Tue, 19 Jan 2016 09:31:42 +0000 (10:31 +0100)
committerabn <adrien.bruneton@cea.fr>
Tue, 1 Mar 2016 09:56:53 +0000 (10:56 +0100)
src/MEDCoupling/MEDCouplingUMesh.cxx
src/MEDLoader/MEDFileMesh.cxx
src/MEDLoader/Swig/MEDLoaderTest3.py

index 7d470fc0f21f668fd9cd2211efe7f000202a02f3..e1b578f5e276db5b8e4621aa6560950583bb6eb5 100644 (file)
@@ -2439,6 +2439,7 @@ void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1On
                                             DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
 {
   typedef MEDCouplingAutoRefCountObjectPtr<DataArrayInt> DAInt;
+  typedef MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> MCUMesh;
 
   checkFullyDefined();
   otherDimM1OnSameCoords.checkFullyDefined();
@@ -2446,21 +2447,62 @@ void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1On
     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
-  DataArrayInt *cellIdsRk0=0,*cellIdsRk1=0;
-  findCellIdsLyingOn(otherDimM1OnSameCoords,cellIdsRk0,cellIdsRk1);
-  DAInt cellIdsRk0Auto(cellIdsRk0),cellIdsRk1Auto(cellIdsRk1);
-  DAInt s0=cellIdsRk1->buildComplement(cellIdsRk0->getNumberOfTuples());
-  s0->transformWithIndArr(cellIdsRk0Auto->begin(),cellIdsRk0Auto->end());
-  MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m0Part=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0->begin(),s0->end(),true));
-  DAInt s1=m0Part->computeFetchedNodeIds();
-  DAInt s2=otherDimM1OnSameCoords.computeFetchedNodeIds();
-  DAInt s3=s2->buildSubstraction(s1);
-  cellIdsRk1->transformWithIndArr(cellIdsRk0Auto->begin(),cellIdsRk0Auto->end());
+
+  // Checking star-shaped M1 group:
+  DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
+  MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
+  DAInt dsi = rdit0->deltaShiftIndex();
+  DAInt idsTmp0 = dsi->getIdsNotInRange(-1, 3);
+  if(idsTmp0->getNumberOfTuples())
+    throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
+  dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
+
+  // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
+  DAInt xtremIdsM2 = dsi->getIdsEqual(1); dsi = 0;
+  MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
+  DAInt xtrem = meshM2Part->computeFetchedNodeIds();
+  // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
+  dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
+  MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
+  dsi = rdit0->deltaShiftIndex();
+  DAInt boundSegs = dsi->getIdsEqual(1);   // boundary segs/faces of the M0 mesh
+  MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
+  DAInt fNodes = m0descSkin->computeFetchedNodeIds();
+  // In 3D, some points on the boundary of M0 still need duplication:
+  DAInt notDup = 0;
+  if (getMeshDimension() == 3)
+    {
+      DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
+      MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
+      dnu1=0;dnu2=0;dnu3=0;dnu4=0;
+      DataArrayInt * corresp=0;
+      meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
+      DAInt validIds = corresp->getIdsInRange(0, meshM2->getNumberOfCells());
+      corresp->decrRef();
+      if (validIds->getNumberOfTuples())
+        {
+          MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
+          DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
+          DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
+          notDup = xtrem->buildSubstraction(fNodes1);
+        }
+      else
+        notDup = xtrem->buildSubstraction(fNodes);
+    }
+  else
+    notDup = xtrem->buildSubstraction(fNodes);
+
+  // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
+  DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
+  DAInt dupl = m1Nodes->buildSubstraction(notDup);
+  DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false);  // false= take cell in, even if not all nodes are in notDup
+
   //
-  MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellIdsRk1->begin(),cellIdsRk1->end(),true));
+  MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
   int nCells2 = m0Part2->getNumberOfCells();
   DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
-  MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
+  MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
+
   // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
   DataArrayInt *tmp00=0,*tmp11=0;
   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
@@ -2470,8 +2512,6 @@ void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1On
   DataArrayInt *idsTmp=0;
   bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
   DAInt ids(idsTmp);
-  if(!b)
-    throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the given mdim-1 mesh in other is not a constituent of this !");
   // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
   // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
   MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
@@ -2517,12 +2557,12 @@ void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1On
     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
 
   DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
-  cellsToModifyConn0_torenum->transformWithIndArr(cellIdsRk1->begin(),cellIdsRk1->end());
-  cellsToModifyConn1_torenum->transformWithIndArr(cellIdsRk1->begin(),cellIdsRk1->end());
+  cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
+  cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
   //
   cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
   cellIdsNotModified=cellsToModifyConn1_torenum.retn();
-  nodeIdsToDuplicate=s3.retn();
+  nodeIdsToDuplicate=dupl.retn();
 }
 
 /*!
index 525cea58caaed61f6af32d19b982f65b69a4d5fa..5198f74620d060d09238821d1fb0bd9142db376f 100644 (file)
@@ -3780,7 +3780,9 @@ void MEDFileUMesh::optimizeFamilies()
  * The boundary is built according to the following method:
  *  - all nodes along the boundary which are not lying on an internal extremity of the (-1)-level group are duplicated (so the
  * coordinates array is extended).
- *  - new (-1)-level cells are built lying on those new nodes. So the edges/faces along the group are duplicated.
+ *  - new (-1)-level cells are built lying on those new nodes. So the edges/faces along the group are duplicated. A new group
+ *  called "<grpNameM1>_dup" containing the effectively duplicated cells is created. Note that in 3D some cells of the group
+ *  might not be duplicated at all.
  *  After this operation a top-level cell bordering the group will loose some neighbors (typically the cell which is  on the
  *  other side of the group is no more a neighbor)
  *   - finally, the connectivity of (part of) the top level-cells bordering the group is also modified so that some cells
@@ -3798,53 +3800,61 @@ void MEDFileUMesh::optimizeFamilies()
 void MEDFileUMesh::buildInnerBoundaryAlongM1Group(const std::string& grpNameM1, DataArrayInt *&nodesDuplicated,
                                            DataArrayInt *&cellsModified, DataArrayInt *&cellsNotModified)
 {
+  typedef MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> MUMesh;
+  typedef MEDCouplingAutoRefCountObjectPtr<DataArrayInt> DAInt;
+
   std::vector<int> levs=getNonEmptyLevels();
   if(std::find(levs.begin(),levs.end(),0)==levs.end() || std::find(levs.begin(),levs.end(),-1)==levs.end())
     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group : This method works only for mesh definied on level 0 and -1 !");
-  MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m0=getMeshAtLevel(0);
-  MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m1=getMeshAtLevel(-1);
+  MUMesh m0=getMeshAtLevel(0);
+  MUMesh m1=getMeshAtLevel(-1);
   int nbNodes=m0->getNumberOfNodes();
-  MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m11=getGroup(-1,grpNameM1);
+  MUMesh m11=getGroup(-1,grpNameM1);
   DataArrayInt *tmp00=0,*tmp11=0,*tmp22=0;
   m0->findNodesToDuplicate(*m11,tmp00,tmp11,tmp22);
-  MEDCouplingAutoRefCountObjectPtr<DataArrayInt> nodeIdsToDuplicate(tmp00);
-  MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsToModifyConn0(tmp11);
-  MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsToModifyConn1(tmp22);
-  MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> tmp0=static_cast<MEDCouplingUMesh *>(m0->buildPartOfMySelf(cellsToModifyConn0->begin(),cellsToModifyConn0->end(),true));
+  DAInt nodeIdsToDuplicate(tmp00);
+  DAInt cellsToModifyConn0(tmp11);
+  DAInt cellsToModifyConn1(tmp22);
+  MUMesh tmp0=static_cast<MEDCouplingUMesh *>(m0->buildPartOfMySelf(cellsToModifyConn0->begin(),cellsToModifyConn0->end(),true));
   // node renumbering of cells in m1 impacted by duplication of node but not in group 'grpNameM1' on level -1
-  MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descTmp0=DataArrayInt::New(),descITmp0=DataArrayInt::New(),revDescTmp0=DataArrayInt::New(),revDescITmp0=DataArrayInt::New();
-  MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> tmp0Desc=tmp0->buildDescendingConnectivity(descTmp0,descITmp0,revDescTmp0,revDescITmp0);
+  DAInt descTmp0=DataArrayInt::New(),descITmp0=DataArrayInt::New(),revDescTmp0=DataArrayInt::New(),revDescITmp0=DataArrayInt::New();
+  MUMesh tmp0Desc=tmp0->buildDescendingConnectivity(descTmp0,descITmp0,revDescTmp0,revDescITmp0);
   descTmp0=0; descITmp0=0; revDescTmp0=0; revDescITmp0=0;
-  MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsInM1ToRenumW2=tmp0Desc->getCellIdsLyingOnNodes(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end(),false);
-  MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> cellsInM1ToRenumW3=static_cast<MEDCouplingUMesh *>(tmp0Desc->buildPartOfMySelf(cellsInM1ToRenumW2->begin(),cellsInM1ToRenumW2->end(),true));
+  DAInt cellsInM1ToRenumW2=tmp0Desc->getCellIdsLyingOnNodes(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end(),false);
+  MUMesh cellsInM1ToRenumW3=static_cast<MEDCouplingUMesh *>(tmp0Desc->buildPartOfMySelf(cellsInM1ToRenumW2->begin(),cellsInM1ToRenumW2->end(),true));
   DataArrayInt *cellsInM1ToRenumW4Tmp=0;
   m1->areCellsIncludedIn(cellsInM1ToRenumW3,2,cellsInM1ToRenumW4Tmp);
-  MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsInM1ToRenumW4(cellsInM1ToRenumW4Tmp);
-  MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsInM1ToRenumW5=cellsInM1ToRenumW4->getIdsInRange(0,m1->getNumberOfCells());
+  DAInt cellsInM1ToRenumW4(cellsInM1ToRenumW4Tmp);
+  DAInt cellsInM1ToRenumW5=cellsInM1ToRenumW4->getIdsInRange(0,m1->getNumberOfCells());
   cellsInM1ToRenumW5->transformWithIndArr(cellsInM1ToRenumW4->begin(),cellsInM1ToRenumW4->end());
-  MEDCouplingAutoRefCountObjectPtr<DataArrayInt> grpIds=getGroupArr(-1,grpNameM1);
-  MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsInM1ToRenum=cellsInM1ToRenumW5->buildSubstraction(grpIds);
-  MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m1Part=static_cast<MEDCouplingUMesh *>(m1->buildPartOfMySelf(cellsInM1ToRenum->begin(),cellsInM1ToRenum->end(),true));
+  DAInt grpIds=getGroupArr(-1,grpNameM1);
+  DAInt cellsInM1ToRenum=cellsInM1ToRenumW5->buildSubstraction(grpIds);
+  MUMesh m1Part=static_cast<MEDCouplingUMesh *>(m1->buildPartOfMySelf(cellsInM1ToRenum->begin(),cellsInM1ToRenum->end(),true));
   m1Part->duplicateNodesInConn(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end(),nbNodes);
   m1->setPartOfMySelf(cellsInM1ToRenum->begin(),cellsInM1ToRenum->end(),*m1Part);
   // end of node renumbering of cells in m1 impacted by duplication of node but not in group of level -1 'grpNameM1'
   tmp0->duplicateNodes(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end());
   m0->setCoords(tmp0->getCoords());
   m0->setPartOfMySelf(cellsToModifyConn0->begin(),cellsToModifyConn0->end(),*tmp0);
+  _ms[0]->forceComputationOfParts();  // necessary because we modify the connectivity of some internal part
   m1->setCoords(m0->getCoords());
   _coords=m0->getCoords(); _coords->incrRef();
-  // duplication of cells in group 'grpNameM1' on level -1
+  // duplication of cells in group 'grpNameM1' on level -1, but not duplicating cells for which nothing has changed
   m11->duplicateNodesInConn(nodeIdsToDuplicate->begin(),nodeIdsToDuplicate->end(),nbNodes); m11->setCoords(m0->getCoords());
-  std::vector<const MEDCouplingUMesh *> v(2); v[0]=m1; v[1]=m11;
-  MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> newm1=MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(v,tmp00,tmp11);
-  MEDCouplingAutoRefCountObjectPtr<DataArrayInt> szOfCellGrpOfSameType(tmp00);
-  MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idInMsOfCellGrpOfSameType(tmp11);
+  DataArrayInt * duplCells;
+  m1->areCellsIncludedIn(m11, 0, duplCells);
+  DAInt zeIds = duplCells->getIdsNotInRange(-1, m1->getNumberOfCells()-1); duplCells->decrRef();
+  MUMesh m11Part=static_cast<MEDCouplingUMesh *>(m11->buildPartOfMySelf(zeIds->begin(),zeIds->end(),true));
+  std::vector<const MEDCouplingUMesh *> v(2); v[0]=m1; v[1]=m11Part;
+  MUMesh newm1=MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(v,tmp00,tmp11);
+  DAInt szOfCellGrpOfSameType(tmp00);
+  DAInt idInMsOfCellGrpOfSameType(tmp11);
   //
   newm1->setName(getName());
   const DataArrayInt *fam=getFamilyFieldAtLevel(-1);
   if(!fam)
-    throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group : internal problem !");
-  MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newFam=DataArrayInt::New();
+    throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group(): internal error no family field !");
+  DAInt newFam=DataArrayInt::New();
   newFam->alloc(newm1->getNumberOfCells(),1);
   // Get a new family ID: care must be taken if we need a positive ID or a negative one:
   // Positive ID for family of nodes, negative for all the rest.
@@ -3861,7 +3871,7 @@ void MEDFileUMesh::buildInnerBoundaryAlongM1Group(const std::string& grpNameM1,
       if(idInMsOfCellGrpOfSameType->getIJ(i,0)==0)
         {
           end=start+szOfCellGrpOfSameType->getIJ(i,0);
-          MEDCouplingAutoRefCountObjectPtr<DataArrayInt> part=fam->selectByTupleId2(start,end,1);
+          DAInt part=fam->selectByTupleId2(start,end,1);
           newFam->setPartOfValues1(part,globStart,globEnd,1,0,1,1,true);
           start=end;
         }
@@ -3888,6 +3898,14 @@ void MEDFileUMesh::buildInnerBoundaryAlongM1Group(const std::string& grpNameM1,
       _fam_coords=newFam;
     }
 
+  _num_coords = 0;
+  _rev_num_coords = 0;
+  for (std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::iterator it=_ms.begin();
+      it != _ms.end(); it++)
+    {
+      (*it)->_num = 0;
+      (*it)->_rev_num = 0;
+    }
   nodesDuplicated=nodeIdsToDuplicate.retn();
   cellsModified=cellsToModifyConn0.retn();
   cellsNotModified=cellsToModifyConn1.retn();
index 84fcb203d2be3d16e261edd386a9c6008f759874..534a09ae1cf3055cec2e4fcec497c8f302862c1a 100644 (file)
@@ -1373,6 +1373,119 @@ class MEDLoaderTest3(unittest.TestCase):
         self.assertTrue(delta.getMaxValue()[0]<1e-12)
         mm.write(fname,2)   
 
+    def testBuildInnerBoundaryAlongM1Group4(self):
+        """ Test case where cells touch the M1 group on some nodes only and not on full egdes (triangle mesh for ex)
+        """
+        coo = DataArrayDouble([0.,0., 1.,0., 2.,0., 3.,0.,
+                               0.,1., 1.,1., 2.,1., 3.,1.,
+                               0.,2., 1.,2., 2.,2., 3.,2.], 12, 2)
+        conn = [3,0,4,1,  3,1,4,5,
+                3,5,9,10, 3,5,10,6,
+                3,2,6,7,  3,2,7,3,
+                3,4,8,9,  3,4,9,5,
+                3,1,5,6,  3,1,6,2,
+                3,6,10,11,3,6,11,7]
+        # Only TRI3:
+        connI = DataArrayInt()
+        connI.alloc(13, 1); connI.iota(); connI *= 4
+        m2 = MEDCouplingUMesh("2D", 2)
+        m2.setCoords(coo)
+        m2.setConnectivity(DataArrayInt(conn), connI)
+        m2.checkCoherency()
+        m1, _, _, _, _ = m2.buildDescendingConnectivity()
+        grpIds = DataArrayInt([9,11]); grpIds.setName("group")
+        grpIds2 = DataArrayInt([0,1]); grpIds2.setName("group2")
+        mfu = MEDFileUMesh()
+        mfu.setMeshAtLevel(0, m2)
+        mfu.setMeshAtLevel(-1, m1)
+        mfu.setGroupsAtLevel(-1, [grpIds, grpIds2])
+        nNod = m2.getNumberOfNodes()
+        nodesDup, cells1, cells2 = mfu.buildInnerBoundaryAlongM1Group("group")
+        m2_bis = mfu.getMeshAtLevel(0)
+        m2_bis.checkCoherency()
+        m1_bis = mfu.getMeshAtLevel(-1)
+        m1_bis.checkCoherency()
+        self.assertEqual(nNod+2, mfu.getNumberOfNodes())
+        self.assertEqual(nNod+2, m2_bis.getNumberOfNodes())
+        self.assertEqual(nNod+2, m1_bis.getNumberOfNodes())
+        self.assertEqual([6,7], nodesDup.getValues())
+        self.assertEqual([2.,1., 3.,1.], m2_bis.getCoords()[nNod:].getValues())
+        self.assertEqual(set([3,10,11]), set(cells1.getValues()))
+        self.assertEqual(set([8,9,4,5]), set(cells2.getValues()))
+        self.assertEqual([9,11],mfu.getGroupArr(-1,"group").getValues())
+        self.assertEqual([23,24],mfu.getGroupArr(-1,"group_dup").getValues())
+        self.assertEqual([0,1],mfu.getGroupArr(-1,"group2").getValues())
+#         mfu.getMeshAtLevel(0).writeVTK("/tmp/mfu_M0.vtu")
+        ref0 =[3, 5, 10, 12, 3, 12, 10, 11, 3, 12, 11, 13]
+        ref1 =[3, 2, 6, 7, 3, 2, 7, 3, 3, 1, 5, 6, 3, 1, 6, 2]
+        self.assertEqual(ref0,mfu.getMeshAtLevel(0)[[3,10,11]].getNodalConnectivity().getValues())
+        self.assertEqual(ref1,mfu.getMeshAtLevel(0)[[4,5,8,9]].getNodalConnectivity().getValues())
+        self.assertRaises(InterpKernelException,mfu.getGroup(-1,"group_dup").checkGeoEquivalWith,mfu.getGroup(-1,"group"),2,1e-12) # Grp_dup and Grp are not equal considering connectivity only
+        mfu.getGroup(-1,"group_dup").checkGeoEquivalWith(mfu.getGroup(-1,"group"),12,1e-12)# Grp_dup and Grp are equal considering connectivity and coordinates
+        m_bis0 = mfu.getMeshAtLevel(-1)
+        m_desc, _, _, _, _ = m_bis0.buildDescendingConnectivity()
+        m_bis0.checkDeepEquivalOnSameNodesWith(mfu.getMeshAtLevel(-1), 2, 9.9999999)
+
+    def testBuildInnerBoundary5(self):
+        """ Full 3D test with tetras only. In this case a tri from the group is not duplicated because it is made only
+        of non duplicated nodes. The tri in question is hence not part of the final new "dup" group. """
+        coo = DataArrayDouble([200.0, 200.0, 0.0, 200.0, 200.0, 200.0, 200.0, 0.0, 200.0, 200.0, 0.0, 0.0, 0.0, 200.0, 0.0, 0.0, 200.0, 200.0, 0.0, 0.0, 0.0, 0.0, 0.0, 
+        200.0, 400.0, 200.0, 0.0, 400.0, 200.0, 200.0, 400.0, 0.0, 0.0, 400.0, 0.0, 200.0, 0.0, 100.00000000000016, 200.0, 63.15203310314546, 200.0, 200.0, 134.45205700643342,
+         200.0, 200.0, 200.0, 100.00000000000016, 200.0, 63.15203310314546, 0.0, 200.0, 134.45205700643342, 0.0, 200.0, 0.0, 100.00000000000016, 0.0, 63.15203310314546, 
+         200.0, 0.0, 134.45205700643342, 200.0, 0.0, 200.0, 100.00000000000016, 0.0, 63.15203310314546, 0.0, 0.0, 134.45205700643342, 0.0, 0.0, 200.0, 200.0, 100.02130053568538, 
+         0.0, 200.0, 100.00938163175135, 200.0, 0.0, 100.02130053568538, 0.0, 0.0, 100.00938163175135, 299.3058739933347, 200.0, 200.0, 400.0, 98.68100542924483, 
+         200.0, 302.8923433403344, 0.0, 200.0, 302.8923433403344, 200.0, 0.0, 400.0, 100.00000000000016, 0.0, 302.8923433403344, 0.0, 0.0, 400.0, 200.0, 98.55126825835082, 
+         400.0, 0.0, 100.02162286181577, 99.31624553977466, 99.99999998882231, 200.0, 99.31624576683302, 100.00000010178034, 0.0, 99.31624560596512, 200.0, 100.0050761312483,
+         99.31624560612883, 0.0, 100.00507613125338, 200.0, 99.99999995813045, 100.00950673487786, 0.0, 99.99999989928207, 100.0041870621175, 301.29063354383015, 
+         100.0000000093269, 0.0, 301.29063360689975, 0.0, 100.00957769061164, 140.52853868782435, 99.99999963972768, 100.00509135751312, 297.87779091770784, 
+         97.16750463405486, 97.18018457127863], 46, 3)
+        c0 = [14, 45, 31, 21, 42, 14, 37, 38, 20, 44, 14, 39, 36, 41, 44, 14, 5, 25, 12, 13, 14, 38, 36, 44, 41, 14, 21, 20, 24, 44, 14, 38, 25, 41, 19, 14, 37, 38, 44, 41, 14, 16, 27,
+         39, 41, 14, 21, 45, 26, 40, 14, 39, 37, 44, 41, 14, 14, 15, 24, 44, 14, 25, 38, 41, 13, 14, 27, 18, 6, 22, 14, 38, 36, 41, 13, 14, 44, 14, 15, 36, 14, 44, 23, 39, 26, 14,
+         21,26, 23, 44, 14, 38, 44, 14, 24, 14, 39, 37, 41, 22, 14, 21, 33, 45, 42, 14, 27, 22, 39, 41, 14, 23, 26, 21, 3, 14, 27, 18, 22, 41, 14, 39, 36, 44, 17, 14, 21, 26, 44, 40,
+         14, 39, 37, 22, 23, 14, 37, 38, 41, 19, 14, 25, 12, 13, 41, 14, 30, 26, 43, 45, 14, 38, 36, 13, 14, 14, 12, 36, 13, 41, 14, 20, 44, 21, 37, 14, 16, 36, 12, 41, 14, 39, 36,
+         17, 16, 14, 44, 20, 24, 38, 14, 27, 16, 12, 41, 14, 26, 15, 17, 44, 14, 19, 18, 41, 37, 14, 40, 45, 26, 15, 14, 37, 38, 19, 20, 14, 17, 15, 26, 2, 14, 39, 36, 16, 41, 14,
+         24, 21, 44, 40, 14, 16, 7, 27, 12, 14, 22, 18, 37, 41, 14, 21, 31, 45, 24, 14, 44, 40, 15, 24, 14, 24, 45, 15, 28, 14, 44, 40, 26, 15, 14, 24, 20, 21, 0, 14, 38, 36, 14,
+         44, 14, 39, 37, 23, 44, 14, 45, 31, 42, 32, 14, 25, 18, 19, 4, 14, 36, 44, 17, 15, 14, 25, 19, 18, 41, 14, 24, 15, 14, 1, 14, 45, 24, 34, 28, 14, 35, 45, 30, 43, 14, 17,
+         44, 39, 26, 14, 44, 23, 21, 37, 14, 30, 45, 29, 15, 14, 45, 35, 33, 43, 14, 30, 15, 26, 45, 14, 31, 21, 0, 24, 14, 33, 35, 32, 10, 14, 29, 45, 34, 28, 14, 32, 45, 34,
+         29, 14, 45, 31, 32, 34, 14, 33, 26, 45, 43, 14, 45, 31, 34, 24, 14, 33, 26, 21, 45, 14, 11, 30, 35, 29, 14, 33, 35, 45, 32, 14, 33, 45, 42, 32, 14, 32, 8, 34, 31, 14,
+         21, 26, 33, 3, 14, 35, 45, 32, 29, 14, 29, 34, 9, 28, 14, 15, 45, 24, 40, 14, 29, 45, 28, 15, 14, 21, 24, 45, 40, 14, 24, 15, 1, 28, 14, 35, 45, 29, 30, 14, 26, 15,
+         30, 2]
+        cI0 = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 175, 180, 185,
+         190, 195, 200, 205, 210, 215, 220, 225, 230, 235, 240, 245, 250, 255, 260, 265, 270, 275, 280, 285, 290, 295, 300, 305, 310, 315, 320, 325, 330, 335, 340, 345, 350, 355, 
+         360, 365, 370, 375, 380, 385, 390, 395, 400, 405, 410, 415, 420, 425, 430]
+        m3 = MEDCouplingUMesh("3D", 3)
+        m3.setCoords(coo)
+        m3.setConnectivity(DataArrayInt(c0), DataArrayInt(cI0))
+        m3.checkCoherency1()
+        m2, _, _, _, _ = m3.buildDescendingConnectivity()
+        grpIds = DataArrayInt([36,74]); grpIds.setName("group")
+        mfu = MEDFileUMesh()
+        mfu.setMeshAtLevel(0, m3)
+        mfu.setMeshAtLevel(-1, m2)
+        grpIds3D = DataArrayInt([0,1]); grpIds3D.setName("group_3d")
+        mfu.setGroupsAtLevel(0, [grpIds3D])  # just to check preservation of 3D group
+        mfu.setGroupsAtLevel(-1, [grpIds])
+        nNod = m3.getNumberOfNodes()
+        nodesDup, cells1, cells2 = mfu.buildInnerBoundaryAlongM1Group("group")
+        m3_bis = mfu.getMeshAtLevel(0)
+        m3_bis.checkCoherency()
+        m2_bis = mfu.getMeshAtLevel(-1)
+        m2_bis.checkCoherency1()
+        self.assertEqual(nNod+1, mfu.getNumberOfNodes())
+        self.assertEqual(nNod+1, m3_bis.getNumberOfNodes())
+        self.assertEqual(nNod+1, m2_bis.getNumberOfNodes())
+        self.assertEqual([3], nodesDup.getValues())
+        self.assertEqual(m3_bis.getCoords()[3].getValues(), m3_bis.getCoords()[nNod:].getValues())
+        self.assertEqual(set([22]), set(cells1.getValues()))
+        self.assertEqual(set([77]), set(cells2.getValues()))
+        self.assertEqual([36,74],mfu.getGroupArr(-1,"group").getValues())
+        self.assertEqual([0,1],mfu.getGroupArr(0,"group_3d").getValues())
+        self.assertEqual([213],mfu.getGroupArr(-1,"group_dup").getValues())  # here only one cell has been duplicated
+        m_bis0 = mfu.getMeshAtLevel(-1)
+        m_desc, _, _, _, _ = m_bis0.buildDescendingConnectivity()
+        m_bis0.checkDeepEquivalOnSameNodesWith(mfu.getMeshAtLevel(-1), 2, 9.9999999)
+        pass
+
     def testBasicConstructors(self):
         fname="Pyfile18.med"
         m=MEDFileMesh.New(fname)