From 9ab46e077076570838f64313913f8a0a1aabdf8e Mon Sep 17 00:00:00 2001 From: vincentcasseau Date: Thu, 12 Sep 2024 16:50:59 +0200 Subject: [PATCH] Generator: close: export vertex indirection table --- Cassiopee/Generator/Generator/Generator.py | 25 ++++++--- Cassiopee/Generator/Generator/PyTree.py | 15 ++++-- Cassiopee/Generator/Generator/close.cpp | 8 +-- Cassiopee/Generator/test/closePT_t1.py | 6 +++ Cassiopee/Generator/test/close_t1.py | 6 ++- Cassiopee/KCore/KCore/Connect/connect.h | 9 ++-- .../KCore/Connect/v_cleanConnectivity.cpp | 54 ++++++++++++++----- 7 files changed, 88 insertions(+), 35 deletions(-) diff --git a/Cassiopee/Generator/Generator/Generator.py b/Cassiopee/Generator/Generator/Generator.py index bddbf03b1..17f6a3d58 100755 --- a/Cassiopee/Generator/Generator/Generator.py +++ b/Cassiopee/Generator/Generator/Generator.py @@ -829,27 +829,36 @@ def closeLegacy(array, tol=1.e-12, suppressDegeneratedNGons=False): def close(array, tol=1.e-12, rmOverlappingPts=True, rmOrphanPts=True, rmDuplicatedFaces=True, rmDuplicatedElts=True, - rmDegeneratedFaces=True, rmDegeneratedElts=True): + rmDegeneratedFaces=True, rmDegeneratedElts=True, + indices=None): """Close an unstructured mesh defined by an array gathering points closer than tol. Usage: close(array, tol)""" + exportIndirPts = False + if isinstance(indices, list) and not indices: exportIndirPts = True if isinstance(array[0], list): out = [] for a in array: + indirl = None if len(a) == 5: # merge intra-borders (C-type meshes) outl = generator.closeBorders([a], [], tol)[0] else: outl = generator.closeMesh(a, tol, rmOverlappingPts, rmOrphanPts, rmDuplicatedFaces, - rmDuplicatedElts, - rmDegeneratedFaces, - rmDegeneratedElts) + rmDuplicatedElts, rmDegeneratedFaces, + rmDegeneratedElts, exportIndirPts) + if exportIndirPts: outl, indirl = outl out.append(outl) + if exportIndirPts: indices.append(indirl) return out else: - return generator.closeMesh(array, tol, rmOverlappingPts, - rmOrphanPts, rmDuplicatedFaces, - rmDuplicatedElts, rmDegeneratedFaces, - rmDegeneratedElts) + out = generator.closeMesh(array, tol, rmOverlappingPts, + rmOrphanPts, rmDuplicatedFaces, + rmDuplicatedElts, rmDegeneratedFaces, + rmDegeneratedElts, exportIndirPts) + if exportIndirPts: + out, indirl = out + indices.append(indirl) + return out def zip(array, tol=1e-12): """Zip a set of meshes defined by gathering exterior points closer than tol. diff --git a/Cassiopee/Generator/Generator/PyTree.py b/Cassiopee/Generator/Generator/PyTree.py index fc2532e91..7685afbed 100644 --- a/Cassiopee/Generator/Generator/PyTree.py +++ b/Cassiopee/Generator/Generator/PyTree.py @@ -844,22 +844,27 @@ def _closeLegacy(t, tol=1.e-12, suppressDegeneratedNGons=False): def close(a, tol=1.e-12, rmOverlappingPts=True, rmOrphanPts=True, rmDuplicatedFaces=True, rmDuplicatedElts=True, - rmDegeneratedFaces=True, rmDegeneratedElts=True): + rmDegeneratedFaces=True, rmDegeneratedElts=True, + indices=None): """Merge vertices distant of tol and remove multiply defined vertices/faces/elements. Usage: close(array, tol, rmOverlappingPts, rmOrphanPts, rmDuplicatedFaces, - rmDuplicatedElts, rmDegeneratedFaces, rmDegeneratedElts)""" + rmDuplicatedElts, rmDegeneratedFaces, rmDegeneratedElts, + indices)""" t = Internal.copyRef(a) _close(t, tol, rmOverlappingPts, rmOrphanPts, rmDuplicatedFaces, - rmDuplicatedElts, rmDegeneratedFaces, rmDegeneratedElts) + rmDuplicatedElts, rmDegeneratedFaces, rmDegeneratedElts, + indices=indices) return t def _close(t, tol=1.e-12, rmOverlappingPts=True, rmOrphanPts=True, rmDuplicatedFaces=True, rmDuplicatedElts=True, - rmDegeneratedFaces=True, rmDegeneratedElts=True): + rmDegeneratedFaces=True, rmDegeneratedElts=True, + indices=None): fields = C.getAllFields(t, 'nodes') fields = Generator.close(fields, tol, rmOverlappingPts, rmOrphanPts, rmDuplicatedFaces, rmDuplicatedElts, - rmDegeneratedFaces, rmDegeneratedElts) + rmDegeneratedFaces, rmDegeneratedElts, + indices=indices) C.setFields(fields, t, 'nodes') return None diff --git a/Cassiopee/Generator/Generator/close.cpp b/Cassiopee/Generator/Generator/close.cpp index 761526726..66cc9becf 100644 --- a/Cassiopee/Generator/Generator/close.cpp +++ b/Cassiopee/Generator/Generator/close.cpp @@ -40,11 +40,13 @@ PyObject* K_GENERATOR::closeMesh(PyObject* self, PyObject* args) E_Bool rmDuplicatedElts = true; E_Bool rmDegeneratedFaces = true; E_Bool rmDegeneratedElts = true; + E_Bool exportIndirPts = false; - if (!PYPARSETUPLE_(args, O_ R_ BB_ BBBB_, + if (!PYPARSETUPLE_(args, O_ R_ BBB_ BBBB_, &array, &eps, &rmOverlappingPts, &rmOrphanPts, &rmDuplicatedFaces, &rmDuplicatedElts, - &rmDegeneratedFaces, &rmDegeneratedElts)) return NULL; + &rmDegeneratedFaces, &rmDegeneratedElts, + &exportIndirPts)) return NULL; // Check array E_Int im, jm, km; @@ -84,7 +86,7 @@ PyObject* K_GENERATOR::closeMesh(PyObject* self, PyObject* args) PyObject* tpl = K_CONNECT::V_cleanConnectivity( varString, *f, *cn, eltType, eps, rmOverlappingPts, rmOrphanPts, rmDuplicatedFaces, rmDuplicatedElts, - rmDegeneratedFaces, rmDegeneratedElts); + rmDegeneratedFaces, rmDegeneratedElts, exportIndirPts); RELEASESHAREDU(array, f, cn); if (tpl == NULL) return array; diff --git a/Cassiopee/Generator/test/closePT_t1.py b/Cassiopee/Generator/test/closePT_t1.py index 83722c506..41abc0daf 100644 --- a/Cassiopee/Generator/test/closePT_t1.py +++ b/Cassiopee/Generator/test/closePT_t1.py @@ -21,3 +21,9 @@ a3 = C.convertArray2Tetra(a) a3 = G.close(a3, 1.e-3) test.testT(a3, 3) + +# test close non structure tetra avec retour de la table d indir. des vertices +indices = [] +a3 = C.convertArray2Tetra(a) +a3 = G.close(a3, 1.e-3, indices=indices) +test.testO(indices, 4) diff --git a/Cassiopee/Generator/test/close_t1.py b/Cassiopee/Generator/test/close_t1.py index fce91e0be..2659e4cd2 100644 --- a/Cassiopee/Generator/test/close_t1.py +++ b/Cassiopee/Generator/test/close_t1.py @@ -20,9 +20,11 @@ a3 = G.close(a3, 1.e-3) test.testA([a3], 3) -# test close NGON +# test close NGON avec retour de la table d indir. des vertices +indices = [] a4 = G.cylinder((0.,0.,0.), 0.5, 1., 360., 0.01, 10., (10,10,10)) a4 = C.convertArray2NGon(a4) a4 = C.addVars(a4, 'F') -a4 = G.close(a4, 5.e-3) +a4 = G.close(a4, 5.e-3, indices=indices) test.testA([a4], 4) +test.testO(indices, 5) diff --git a/Cassiopee/KCore/KCore/Connect/connect.h b/Cassiopee/KCore/KCore/Connect/connect.h index cf5788092..98ba936fb 100644 --- a/Cassiopee/KCore/KCore/Connect/connect.h +++ b/Cassiopee/KCore/KCore/Connect/connect.h @@ -423,7 +423,8 @@ namespace K_CONNECT K_FLD::FldArrayI& cn, const char* eltType, E_Float tol=0., E_Bool rmOverlappingPts=true, E_Bool rmOrphanPts=true, E_Bool rmDuplicatedFaces=true, E_Bool rmDuplicatedElts=true, - E_Bool rmDegeneratedFaces=true, E_Bool rmDegeneratedElts=true); + E_Bool rmDegeneratedFaces=true, E_Bool rmDegeneratedElts=true, + E_Bool exportIndirPts=false); // Clean connectivity - NGON PyObject* V_cleanConnectivityNGon( @@ -431,7 +432,8 @@ namespace K_CONNECT K_FLD::FldArrayF& f, K_FLD::FldArrayI& cn, E_Float tol=0., E_Bool rmOverlappingPts=true, E_Bool rmOrphanPts=true, E_Bool rmDuplicatedFaces=true, E_Bool rmDuplicatedElts=true, - E_Bool rmDegeneratedFaces=true, E_Bool rmDegeneratedElts=true); + E_Bool rmDegeneratedFaces=true, E_Bool rmDegeneratedElts=true, + E_Bool exportIndirPts=false); E_Int V_identifyDirtyPoints( E_Int posx, E_Int posy, E_Int posz, @@ -459,7 +461,8 @@ namespace K_CONNECT E_Int posx, E_Int posy, E_Int posz, const char* varString, K_FLD::FldArrayF& f, K_FLD::FldArrayI& cn, const char* eltType, E_Float tol=0., E_Bool rmOverlappingPts=true, E_Bool rmOrphanPts=true, - E_Bool rmDuplicatedElts=true, E_Bool rmDegeneratedElts=true); + E_Bool rmDuplicatedElts=true, E_Bool rmDegeneratedElts=true, + E_Bool exportIndirPts=false); E_Int V_identifyDirtyElementsME( E_Int dim, K_FLD::FldArrayI& cn, std::vector& indir, diff --git a/Cassiopee/KCore/KCore/Connect/v_cleanConnectivity.cpp b/Cassiopee/KCore/KCore/Connect/v_cleanConnectivity.cpp index 767976bf8..20dd9ec06 100644 --- a/Cassiopee/KCore/KCore/Connect/v_cleanConnectivity.cpp +++ b/Cassiopee/KCore/KCore/Connect/v_cleanConnectivity.cpp @@ -23,6 +23,7 @@ #include #include "Array/Array.h" #include +#include "kcore.h" #include "String/kstring.h" #include "Connect/connect.h" @@ -40,7 +41,7 @@ PyObject* K_CONNECT::V_cleanConnectivity( E_Float tol, E_Bool rmOverlappingPts, E_Bool rmOrphanPts, E_Bool rmDuplicatedFaces, E_Bool rmDuplicatedElts, E_Bool rmDegeneratedFaces, - E_Bool rmDegeneratedElts + E_Bool rmDegeneratedElts, E_Bool exportIndirPts ) { E_Int posx = K_ARRAY::isCoordinateXPresent(varString); @@ -49,27 +50,28 @@ PyObject* K_CONNECT::V_cleanConnectivity( if (posx == -1 || posy == -1 || posz == -1) { PyErr_SetString(PyExc_TypeError, - "cleanConnectivity: coord must be present in array."); + "cleanConnectivity: coords must be present in array."); return NULL; } posx++; posy++; posz++; - PyObject* tpl = NULL; + PyObject* o = NULL; if (K_STRING::cmp(eltType, "NGON") == 0 || K_STRING::cmp(eltType, "NGON*") == 0) { - tpl = V_cleanConnectivityNGon(posx, posy, posz, varString, f, cn, - tol, rmOverlappingPts, rmOrphanPts, - rmDuplicatedFaces, rmDuplicatedElts, - rmDegeneratedFaces, rmDegeneratedElts); + o = V_cleanConnectivityNGon(posx, posy, posz, varString, f, cn, + tol, rmOverlappingPts, rmOrphanPts, + rmDuplicatedFaces, rmDuplicatedElts, + rmDegeneratedFaces, rmDegeneratedElts, + exportIndirPts); } else { - tpl = V_cleanConnectivityME(posx, posy, posz, varString, f, cn, - eltType, tol, rmOverlappingPts, - rmOrphanPts, rmDuplicatedElts, - rmDegeneratedElts); + o = V_cleanConnectivityME(posx, posy, posz, varString, f, cn, + eltType, tol, rmOverlappingPts, rmOrphanPts, + rmDuplicatedElts, rmDegeneratedElts, + exportIndirPts); } - return tpl; + return o; } // Nettoyage de la connectivite NGON @@ -78,7 +80,8 @@ PyObject* K_CONNECT::V_cleanConnectivityNGon( FldArrayF& f, FldArrayI& cn, E_Float tol, E_Bool rmOverlappingPts, E_Bool rmOrphanPts, E_Bool rmDuplicatedFaces, E_Bool rmDuplicatedElts, - E_Bool rmDegeneratedFaces, E_Bool rmDegeneratedElts + E_Bool rmDegeneratedFaces, E_Bool rmDegeneratedElts, + E_Bool exportIndirPts ) { E_Bool rmDirtyFaces = (rmDuplicatedFaces || rmDegeneratedFaces); @@ -178,6 +181,8 @@ PyObject* K_CONNECT::V_cleanConnectivityNGon( } } } + + if (!exportIndirPts) indir.clear(); // --- 2. Identify dirty elements topologically --- E_Int nuniqueElts = nelts; @@ -365,6 +370,15 @@ PyObject* K_CONNECT::V_cleanConnectivityNGon( RELEASESHAREDU(tpl, f2, cn2); } + + if (exportIndirPts) + { + PyObject* vmap = K_NUMPY::buildNumpyArray(npts, 1, 1); + E_Int* vmapp = K_NUMPY::getNumpyPtrI(vmap); + #pragma omp parallel for + for (E_Int i = 0; i < npts; i++) vmapp[i] = indir[i]; + return Py_BuildValue("(OO)", tpl, vmap); + } return tpl; } @@ -662,7 +676,8 @@ PyObject* K_CONNECT::V_cleanConnectivityME( E_Int posx, E_Int posy, E_Int posz, const char* varString, FldArrayF& f, FldArrayI& cn, const char* eltType, E_Float tol, E_Bool rmOverlappingPts, E_Bool rmOrphanPts, - E_Bool rmDuplicatedElts, E_Bool rmDegeneratedElts + E_Bool rmDuplicatedElts, E_Bool rmDegeneratedElts, + E_Bool exportIndirPts ) { E_Bool rmDirtyElts = (rmDuplicatedElts || rmDegeneratedElts); @@ -777,6 +792,8 @@ PyObject* K_CONNECT::V_cleanConnectivityME( } } } + + if (!exportIndirPts) indir.clear(); // 1.d Resize fields //f.reAllocMat(nuniquePts,nfld); @@ -864,6 +881,15 @@ PyObject* K_CONNECT::V_cleanConnectivityME( } RELEASESHAREDU(tpl, f2, cn2); } + + if (exportIndirPts) + { + PyObject* vmap = K_NUMPY::buildNumpyArray(npts, 1, 1); + E_Int* vmapp = K_NUMPY::getNumpyPtrI(vmap); + #pragma omp parallel for + for (E_Int i = 0; i < npts; i++) vmapp[i] = indir[i]; + return Py_BuildValue("(OO)", tpl, vmap); + } return tpl; }