]> SALOME platform Git repositories - tools/medcoupling.git/commitdiff
Salome HOME
Introduced check functions in MEDFileUMesh:
authorabn <adrien.bruneton@cea.fr>
Fri, 29 Jan 2016 13:34:59 +0000 (14:34 +0100)
committerabn <adrien.bruneton@cea.fr>
Wed, 3 Feb 2016 09:18:06 +0000 (10:18 +0100)
   + checkCoherency(),
   + checkSMESHCoherency()
   + and clearNodeAndCellNumbers()

Also added hasUniqueValues() in DataArrayInt

src/MEDCoupling/MEDCouplingMemArray.cxx
src/MEDCoupling/MEDCouplingMemArray.hxx
src/MEDCoupling_Swig/MEDCouplingBasicsTest2.py
src/MEDCoupling_Swig/MEDCouplingMemArray.i
src/MEDLoader/MEDFileMesh.cxx
src/MEDLoader/MEDFileMesh.hxx
src/MEDLoader/MEDFileMeshLL.cxx
src/MEDLoader/MEDFileMeshLL.hxx
src/MEDLoader/Swig/MEDLoaderCommon.i
src/MEDLoader/Swig/MEDLoaderTest3.py

index 337c822e0877f0c3e77f643fe694a2c307b70a3b..3df9fb6c6bba1e96150cdc94298cad3eb9be8b70 100644 (file)
@@ -7820,6 +7820,24 @@ bool DataArrayInt::isUniform(int val) const
   return true;
 }
 
+/*!
+ * Checks if all values in \a this array are unique.
+ *  \return bool - \a true if condition above is true
+ *  \throw If \a this is not allocated.
+ *  \throw If \a this->getNumberOfComponents() != 1
+ */
+bool DataArrayInt::hasUniqueValues() const
+{
+  checkAllocated();
+  if(getNumberOfComponents()!=1)
+    throw INTERP_KERNEL::Exception("DataArrayInt::hasOnlyUniqueValues: must be applied on DataArrayInt with only one component, you can call 'rearrange' method before !");
+  int nbOfTuples(getNumberOfTuples());
+  std::set<int> s(begin(),end());  // in C++11, should use unordered_set (O(1) complexity)
+  if (s.size() != nbOfTuples)
+    return false;
+  return true;
+}
+
 /*!
  * Creates a new DataArrayDouble and assigns all (textual and numerical) data of \a this
  * array to the new one.
index 93de8ade0e83017d322ad8e28bba2263ea1a9e76..02857f1440e4af59bb71a6df47451bea29b670cd 100644 (file)
@@ -522,6 +522,7 @@ namespace ParaMEDMEM
     MEDCOUPLING_EXPORT DataArrayInt *buildPermArrPerLevel() const;
     MEDCOUPLING_EXPORT bool isIdentity2(int sizeExpected) const;
     MEDCOUPLING_EXPORT bool isUniform(int val) const;
+    MEDCOUPLING_EXPORT bool hasUniqueValues() const;
     MEDCOUPLING_EXPORT DataArrayInt *substr(int tupleIdBg, int tupleIdEnd=-1) const;
     MEDCOUPLING_EXPORT void rearrange(int newNbOfCompo);
     MEDCOUPLING_EXPORT void transpose();
index db3777022aac12847e482f28aedabd10353f8338..f40daab8cc7ef59fa0b61a18033aa2c38a11bb93 100644 (file)
@@ -1870,6 +1870,19 @@ class MEDCouplingBasicsTest2(unittest.TestCase):
         da2.setIJ(1,0,1.+1.e-11);
         self.assertTrue(not da2.isUniform(1.,1.e-12));
         pass
+
+    def testDAHasUniqueValues1(self):
+        da=DataArrayInt([1,2,3,4,5])
+        self.assertTrue(da.hasUniqueValues())
+        da[1,0] = 5
+        self.assertFalse(da.hasUniqueValues())
+        da=DataArrayInt([])
+        self.assertTrue(da.hasUniqueValues())
+        da=DataArrayInt([(1,2), (2,3)]) # wrong num of compo
+        self.assertRaises(InterpKernelException, da.hasUniqueValues)
+        da=DataArrayInt()  # non allocated array
+        self.assertRaises(InterpKernelException, da.hasUniqueValues)
+        pass
     
     def testDADFromPolarToCart1(self):
         tab1=[2.,0.2,2.5,0.7]
index e13e8eec1f9fdc9f3a7e911ba8dfbf228ce9801a..663e15f921672c69a42d1b2d1e6a13a21d958313 100644 (file)
@@ -2622,6 +2622,7 @@ namespace ParaMEDMEM
     DataArrayInt *buildPermArrPerLevel() const throw(INTERP_KERNEL::Exception);
     bool isIdentity2(int sizeExpected) const throw(INTERP_KERNEL::Exception);
     bool isUniform(int val) const throw(INTERP_KERNEL::Exception);
+    bool hasUniqueValues() const throw(INTERP_KERNEL::Exception);
     DataArrayInt *substr(int tupleIdBg, int tupleIdEnd=-1) const throw(INTERP_KERNEL::Exception);
     void transpose() throw(INTERP_KERNEL::Exception);
     DataArrayInt *changeNbOfComponents(int newNbOfComp, int dftValue) const throw(INTERP_KERNEL::Exception);
index c5c9f58d0535a1d2c92fbb98fe6ef89bd5b57738..a6f24be5678e7bf3ee8a3988c02164f0cfb723ef 100644 (file)
@@ -2488,6 +2488,97 @@ bool MEDFileUMesh::isEqual(const MEDFileMesh *other, double eps, std::string& wh
   return pd0->isEqual(pd1,what);
 }
 
+/*!
+ * Check that the current object MEDFileUMesh is consistent. This does not check the optional renumbering of
+ * nodes and cells. This last item is important for SMESH, see checkSMESHCoherency().
+ * \throw if any internal part (i.e. mesh sub-levels and single geometric-type meshes) are inconsistent
+ * \throw if internal family array is inconsistent
+ * \sa checkSMESHCoherency()
+ */
+void MEDFileUMesh::checkCoherency() const
+{
+  if(!_coords || !_coords->isAllocated())
+    {
+      if(!_ms.size())
+        throw INTERP_KERNEL::Exception("MEDFileUMesh::checkCoherency(): coords are null but some mesh parts are present!");
+      if (!_fam_coords)
+        throw INTERP_KERNEL::Exception("MEDFileUMesh::checkCoherency(): coords are null but not the internal node family array!");
+      if (!_num_coords || !_rev_num_coords)
+        throw INTERP_KERNEL::Exception("MEDFileUMesh::checkCoherency(): coords are null but not the internal node numbering array!");
+    }
+  else
+    {
+      int nbCoo = _coords->getNumberOfTuples();
+      if (_fam_coords)
+        _fam_coords->checkNbOfTuplesAndComp(nbCoo,1,"MEDFileUMesh::checkCoherency(): inconsistent internal node family array!");
+      if (_num_coords)
+        {
+          _num_coords->checkNbOfTuplesAndComp(nbCoo,1,"MEDFileUMesh::checkCoherency(): inconsistent internal node numbering array!");
+          int pos;
+          int maxValue=_num_coords->getMaxValue(pos);
+          if (!_rev_num_coords || _rev_num_coords->getNumberOfTuples() != (maxValue+1))
+            throw INTERP_KERNEL::Exception("MEDFileUMesh::checkCoherency(): inconsistent internal revert node numbering array!");
+        }
+      if ((_num_coords && !_rev_num_coords) || (!_num_coords && _rev_num_coords))
+        throw INTERP_KERNEL::Exception("MEDFileUMesh::checkCoherency(): inconsistent internal numbering arrays (one is null)!");
+      if (_num_coords && !_num_coords->hasUniqueValues())
+        throw INTERP_KERNEL::Exception("MEDFileUMesh::checkCoherency(): inconsistent internal node numbering array: duplicates found!");
+      if (_name_coords)
+        _name_coords->checkNbOfTuplesAndComp(nbCoo,MED_SNAME_SIZE,"MEDFileUMesh::checkCoherency(): inconsistent internal coord name array!");
+      // Now sub part check:
+      for (std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();
+          it != _ms.end(); it++)
+        (*it)->checkCoherency();
+    }
+}
+
+/**
+ * Same as checkCoherency() but also checks that optional entities (edges, faces, volumes) numbers are
+ * consistent, i.e. the numbering is either set to null for all sub-levels (thus letting SMESH numbers the
+ * entities as it likes), or non overlapping between all sub-levels.
+ * \throw if the condition above is not respected
+ */
+void MEDFileUMesh::checkSMESHCoherency() const
+{
+  checkCoherency();
+  // For all sub-levels, numbering is either always null or with void intersection:
+  if (_ms.size())
+    {
+      std::vector< MEDCouplingAutoRefCountObjectPtr<MEDFileUMeshSplitL1> >::const_iterator it=_ms.begin();
+      std::vector< const DataArrayInt * > v;
+      bool voidOrNot = ((*it)->_num == 0);
+      for (it++; it != _ms.end(); it++)
+        if( ((*it)->_num == 0) != voidOrNot )
+          throw INTERP_KERNEL::Exception("MEDFileUMesh::checkCoherency(): inconsistent numbering between mesh sub-levels!");
+        else if (!voidOrNot)
+          v.push_back((*it)->_num);
+      if (!voidOrNot)
+        {
+          // don't forget the 1st one:
+          v.push_back(_ms[0]->_num);
+          MEDCouplingAutoRefCountObjectPtr<DataArrayInt> inter = DataArrayInt::BuildIntersection(v);
+          if (inter->getNumberOfTuples())
+            throw INTERP_KERNEL::Exception("MEDFileUMesh::checkCoherency(): overlapping entity numbering between mesh sub-levels!");
+        }
+    }
+}
+
+/**
+ * Reset optional node and cell numbering for all sub levels in this. This particularly useful to make
+ * sure SMESH will handle the mesh correctly, as it tries to use those numbers if given.
+ */
+void MEDFileUMesh::clearNodeAndCellNumbers()
+{
+  _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;
+    }
+}
+
 /*!
  * Clears redundant attributes of incorporated data arrays.
  */
@@ -3694,12 +3785,15 @@ void MEDFileUMesh::optimizeFamilies()
  *  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
  *  bordering the newly created boundary use the newly computed nodes.
+ *  Finally note that optional cell numbers are also affected by this method and might become invalid for SMESH.
+ *  Use clearNodeAndCellNumbers() afterwards to ensure a proper SMESH loading.
  *
  *  \param[in] grpNameM1 name of the (-1)-level group defining the boundary
  *  \param[out] nodesDuplicated ids of the initial nodes which have been duplicated (and whose copy is put at the end of
  *  the coord array)
  *  \param[out] cellsModified ids of the cells whose connectivity has been modified (to use the newly created nodes)
  *  \param[out] cellsNotModified ids of the rest of cells bordering the new boundary whose connectivity remains unchanged.
+ *  \sa clearNodeAndCellNumbers()
  */
 void MEDFileUMesh::buildInnerBoundaryAlongM1Group(const std::string& grpNameM1, DataArrayInt *&nodesDuplicated,
                                            DataArrayInt *&cellsModified, DataArrayInt *&cellsNotModified)
@@ -3793,6 +3887,7 @@ void MEDFileUMesh::buildInnerBoundaryAlongM1Group(const std::string& grpNameM1,
       newFam->setPartOfValuesSimple1(0,nbNodes,newNbOfNodes,1,0,1,1);
       _fam_coords=newFam;
     }
+
   nodesDuplicated=nodeIdsToDuplicate.retn();
   cellsModified=cellsToModifyConn0.retn();
   cellsNotModified=cellsToModifyConn1.retn();
index b29871d368de58aa9a6ac7c745a0fec197a66ee5..bf8fb184e6e1fcfe55225b253adde520f353c5ee 100644 (file)
@@ -255,6 +255,9 @@ namespace ParaMEDMEM
     MEDLOADER_EXPORT MEDFileMesh *deepCpy() const;
     MEDLOADER_EXPORT MEDFileMesh *shallowCpy() const;
     MEDLOADER_EXPORT bool isEqual(const MEDFileMesh *other, double eps, std::string& what) const;
+    MEDLOADER_EXPORT void checkCoherency() const;
+    MEDLOADER_EXPORT void checkSMESHCoherency() const;
+    MEDLOADER_EXPORT void clearNodeAndCellNumbers();
     MEDLOADER_EXPORT void clearNonDiscrAttributes() const;
     MEDLOADER_EXPORT void setName(const std::string& name);
     //
index ff1afac616a17901ebcb899798caa32c73b7f8a3..4acb989322feffe0a09a09520a2b2c80ee08f492 100644 (file)
@@ -947,6 +947,29 @@ MEDFileUMeshSplitL1 *MEDFileUMeshSplitL1::deepCpy(DataArrayDouble *coords) const
   return ret.retn();
 }
 
+void MEDFileUMeshSplitL1::checkCoherency() const
+{
+  if (!_fam || _fam->getNumberOfTuples() != getSize())
+    throw INTERP_KERNEL::Exception("MEDFileUMeshSplitL1::checkCoherency(): internal family array has an invalid size!");
+  int nbCells = getSize();
+  if (_num)
+    {
+      _num->checkNbOfTuplesAndComp(nbCells,1,"MEDFileUMeshSplitL1::checkCoherency(): inconsistent internal node numbering array!");
+      int pos;
+      int maxValue=_num->getMaxValue(pos);
+      if (!_rev_num || _rev_num->getNumberOfTuples() != (maxValue+1))
+        throw INTERP_KERNEL::Exception("MEDFileUMeshSplitL1::checkCoherency(): inconsistent internal revert node numbering array!");
+    }
+  if ((_num && !_rev_num) || (!_num && _rev_num))
+    throw INTERP_KERNEL::Exception("MEDFileUMeshSplitL1::checkCoherency(): inconsistent internal numbering arrays (one is null)!");
+  if (_num && !_num->hasUniqueValues())
+    throw INTERP_KERNEL::Exception("MEDFileUMeshSplitL1::checkCoherency(): inconsistent internal node numbering array: duplicates found!");
+  if (_names)
+    _names->checkNbOfTuplesAndComp(nbCells,1,"MEDFileUMeshSplitL1::checkCoherency(): internal cell naming array has an invalid size!");
+
+  _m_by_types.checkCoherency();
+}
+
 bool MEDFileUMeshSplitL1::isEqual(const MEDFileUMeshSplitL1 *other, double eps, std::string& what) const
 {
   if(!_m_by_types.isEqual(other->_m_by_types,eps,what))
@@ -1836,6 +1859,16 @@ bool MEDFileUMeshAggregateCompute::isEqual(const MEDFileUMeshAggregateCompute& o
   return true;
 }
 
+void MEDFileUMeshAggregateCompute::checkCoherency() const
+{
+  if(_mp_time >= _m_time)
+    for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDCoupling1GTUMesh> >::const_iterator it=_m_parts.begin();
+        it!=_m_parts.end(); it++)
+      (*it)->checkCoherency1();
+  else
+    _m->checkCoherency1();
+}
+
 void MEDFileUMeshAggregateCompute::clearNonDiscrAttributes() const
 {
   for(std::vector< MEDCouplingAutoRefCountObjectPtr<MEDCoupling1GTUMesh> >::const_iterator it=_m_parts.begin();it!=_m_parts.end();it++)
index f40ccf1ab37dcdfd857f696d9471dc79787e402a..29c943a00ecbb6872fa97b2062f8146e61d057ac 100644 (file)
@@ -186,6 +186,7 @@ namespace ParaMEDMEM
     MEDFileUMeshAggregateCompute deepCpy(DataArrayDouble *coords) const;
     void shallowCpyMeshes();
     bool isEqual(const MEDFileUMeshAggregateCompute& other, double eps, std::string& what) const;
+    void checkCoherency() const;
     void clearNonDiscrAttributes() const;
     void synchronizeTinyInfo(const MEDFileMesh& master) const;
     bool empty() const;
@@ -211,6 +212,7 @@ namespace ParaMEDMEM
   class MEDFileUMeshSplitL1 : public RefCountObject
   {
     friend class MEDFileUMeshPermCompute;
+    friend class MEDFileUMesh;
   public:
     MEDFileUMeshSplitL1(const MEDFileUMeshSplitL1& other);
     MEDFileUMeshSplitL1(const MEDFileUMeshL2& l2, const std::string& mName, int id);
@@ -222,6 +224,7 @@ namespace ParaMEDMEM
     std::vector<const BigMemoryObject *> getDirectChildrenWithNull() const;
     MEDFileUMeshSplitL1 *shallowCpyUsingCoords(DataArrayDouble *coords) const;
     MEDFileUMeshSplitL1 *deepCpy(DataArrayDouble *coords) const;
+    void checkCoherency() const;
     void setCoords(DataArrayDouble *coords);
     bool isEqual(const MEDFileUMeshSplitL1 *other, double eps, std::string& what) const;
     void clearNonDiscrAttributes() const;
index 8e0ef6a2103b25ae1b1b6e9a5f8fdad4b4e95208..73b7803d8a93f4717ef2c786952ed2c42b3578a8 100644 (file)
@@ -1179,6 +1179,9 @@ namespace ParaMEDMEM
     ~MEDFileUMesh();
     int getSpaceDimension() const throw(INTERP_KERNEL::Exception);
     int getRelativeLevOnGeoType(INTERP_KERNEL::NormalizedCellType gt) const throw(INTERP_KERNEL::Exception);
+    void checkCoherency() const throw(INTERP_KERNEL::Exception);
+    void checkSMESHCoherency() const throw(INTERP_KERNEL::Exception);
+    void clearNodeAndCellNumbers();
     //
     MEDCouplingUMesh *getGroup(int meshDimRelToMaxExt, const std::string& grp, bool renum=false) const throw(INTERP_KERNEL::Exception);
     MEDCouplingUMesh *getGroups(int meshDimRelToMaxExt, const std::vector<std::string>& grps, bool renum=false) const throw(INTERP_KERNEL::Exception);
index 9f8a81965e368fbff14fa23594e2362d7bf502b2..84fcb203d2be3d16e261edd386a9c6008f759874 100644 (file)
@@ -4852,6 +4852,103 @@ class MEDLoaderTest3(unittest.TestCase):
       self.assertTrue(mm.getHiddenCppPointer()==mm2.getHiddenCppPointer()) # optimization
       pass
 
+    def testCheckCoherency(self):
+      m2 = MEDCouplingUMesh("2d", 2)
+      m2.setCoords(DataArrayDouble([(0.0, 1.0)] * 4, 4,2))  # whatever
+      m2.setConnectivity(DataArrayInt([NORM_TRI3, 0,1,2,NORM_TRI3, 1,2,3]), DataArrayInt(([0,4,8])))
+      m1 , _, _ , _, _ = m2.buildDescendingConnectivity()
+      mum = MEDFileUMesh()
+      mum.setMeshAtLevel(0, m2)
+      mum.setMeshAtLevel(-1, m1)
+      mum.checkCoherency()
+      mum2 = mum.deepCpy()
+
+      # Nodes
+      arr = DataArrayInt([2]*4)
+      mum.setFamilyFieldArr(1, arr); arr.reAlloc(35);
+      self.assertRaises(InterpKernelException, mum.checkCoherency)
+      mum=mum2; mum2=mum.deepCpy();
+      arr = DataArrayInt([2]*4)
+      mum.setRenumFieldArr(1, arr); arr.reAlloc(35);
+      self.assertRaises(InterpKernelException, mum.checkCoherency)
+      mum=mum2; mum2=mum.deepCpy();
+      mum.setRenumFieldArr(1, DataArrayInt([2]*4))
+      self.assertRaises(InterpKernelException, mum.checkCoherency)
+      mum=mum2; mum2=mum.deepCpy();
+      arr = DataArrayAsciiChar(['tutu           x']*4)
+      mum.setNameFieldAtLevel(1, arr); arr.reAlloc(35);
+      self.assertRaises(InterpKernelException, mum.checkCoherency)
+
+      # 2D
+      mum=mum2; mum2=mum.deepCpy();
+      arr = DataArrayInt([2]*2)
+      mum.setFamilyFieldArr(0, arr); arr.reAlloc(35);
+      self.assertRaises(InterpKernelException, mum.checkCoherency)
+      mum=mum2; mum2=mum.deepCpy();
+      arr = DataArrayInt([2]*2)
+      mum.setRenumFieldArr(0, arr); arr.reAlloc(35);
+      self.assertRaises(InterpKernelException, mum.checkCoherency)
+      mum=mum2; mum2=mum.deepCpy();
+      mum.setRenumFieldArr(0, DataArrayInt([2]*2))
+      self.assertRaises(InterpKernelException, mum.checkCoherency)
+      mum=mum2; mum2=mum.deepCpy();
+      arr = DataArrayAsciiChar(['tutu           x']*2)
+      mum.setNameFieldAtLevel(0, arr); arr.reAlloc(35);
+      self.assertRaises(InterpKernelException, mum.checkCoherency)
+
+      # 1D
+      mum=mum2; mum2=mum.deepCpy();
+      arr = DataArrayInt([2]*5)
+      mum.setFamilyFieldArr(-1, arr); arr.reAlloc(35);
+      self.assertRaises(InterpKernelException, mum.checkCoherency)
+      mum=mum2; mum2=mum.deepCpy();
+      arr = DataArrayInt([2]*5)
+      mum.setRenumFieldArr(-1, arr); arr.reAlloc(35);
+      self.assertRaises(InterpKernelException, mum.checkCoherency)
+      mum=mum2; mum2=mum.deepCpy();
+      mum.setRenumFieldArr(-1, DataArrayInt([2]*5))
+      self.assertRaises(InterpKernelException, mum.checkCoherency)
+      mum=mum2; mum2=mum.deepCpy();
+      arr = DataArrayAsciiChar(['tutu           x']*5)
+      mum.setNameFieldAtLevel(-1, arr); arr.reAlloc(35);
+      self.assertRaises(InterpKernelException, mum.checkCoherency)
+
+    def testCheckSMESHCoherency(self):
+      m2 = MEDCouplingUMesh("2d", 2)
+      m2.setCoords(DataArrayDouble([(0.0, 1.0)] * 4, 4,2))  # whatever
+      m2.setConnectivity(DataArrayInt([NORM_TRI3, 0,1,2,NORM_TRI3, 1,2,3]), DataArrayInt(([0,4,8])))
+      m1 , _, _ , _, _ = m2.buildDescendingConnectivity()
+      mum = MEDFileUMesh()
+      mum.setMeshAtLevel(0, m2)
+      mum.setMeshAtLevel(-1, m1)
+      mum.checkCoherency()
+      mum.checkSMESHCoherency()
+      n2 = DataArrayInt(m2.getNumberOfCells(), 1); n2.iota(1)
+      n1 = DataArrayInt(m1.getNumberOfCells(), 1); n1.iota(1)
+      mum.setRenumFieldArr(0, n2)
+      mum.setRenumFieldArr(-1, n1)
+      self.assertRaises(InterpKernelException, mum.checkSMESHCoherency)
+      mum.setRenumFieldArr(-1, n1+100)
+      mum.checkSMESHCoherency()
+      pass
+
+    def testClearNodeAndCellNumbers(self):
+      m2 = MEDCouplingUMesh("2d", 2)
+      m2.setCoords(DataArrayDouble([(0.0, 1.0)] * 4, 4,2))  # whatever
+      m2.setConnectivity(DataArrayInt([NORM_TRI3, 0,1,2,NORM_TRI3, 1,2,3]), DataArrayInt(([0,4,8])))
+      m1 , _, _ , _, _ = m2.buildDescendingConnectivity()
+      mum = MEDFileUMesh()
+      mum.setMeshAtLevel(0, m2)
+      mum.setMeshAtLevel(-1, m1)
+      mum.checkCoherency()
+      n2 = DataArrayInt(m2.getNumberOfCells(), 1); n2.iota(1)
+      n1 = DataArrayInt(m1.getNumberOfCells(), 1); n1.iota(1)
+      mum.setRenumFieldArr(0, n2)
+      mum.setRenumFieldArr(-1, n1)
+      mum.clearNodeAndCellNumbers()
+      mum.checkSMESHCoherency()
+      pass
+
     pass
 
 if __name__ == "__main__":