From 5eea50975e72b06b30e982fcd8b5b2808ca600b6 Mon Sep 17 00:00:00 2001 From: vincentcasseau Date: Thu, 5 Sep 2024 14:58:23 +0200 Subject: [PATCH 1/3] CPlot: validCassiopee: detecting memory leaks with LSAN rather than test repetitions --- Cassiopee/CPlot/apps/validCassiopee.py | 97 ++++---------------------- Cassiopee/Envs/sh_Cassiopee_local | 2 + Cassiopee/KCore/install | 8 +++ 3 files changed, 25 insertions(+), 82 deletions(-) diff --git a/Cassiopee/CPlot/apps/validCassiopee.py b/Cassiopee/CPlot/apps/validCassiopee.py index 6206d6cb6..6e109229e 100644 --- a/Cassiopee/CPlot/apps/validCassiopee.py +++ b/Cassiopee/CPlot/apps/validCassiopee.py @@ -23,6 +23,7 @@ # Regexprs regDiff = re.compile('DIFF') regFailed = re.compile('FAILED') +regFailedLSAN = re.compile('ERROR: LeakSanitizer: detected memory leaks') regError = re.compile('Error') regErreur = re.compile('Erreur') # because of french system regAbort = re.compile('Aborted') @@ -283,10 +284,9 @@ def check_output(cmd, shell, stderr): stderr=subprocess.PIPE, cwd=wdir, shell=shell, preexec_fn=ossid) - # max accepted time is between 2 to 6 minutes for one repetition of a test - nreps = Repeats.get() + # max accepted time is between 2 to 6 minutes nthreads = float(KCore.kcore.getOmpMaxThreads()) - timeout = nreps*(100. + 120.*Dist.DEBUG)*(1. + 4.8/nthreads) + timeout = (100. + 120.*Dist.DEBUG)*(1. + 4.8/nthreads) stdout, stderr = PROCESS.communicate(None, timeout=timeout) if PROCESS.wait() != 0: stderr += b'\nError: process FAILED (Segmentation Fault or floating point exception).' @@ -550,7 +550,7 @@ def runSingleTest(no, module, test): # retourne le temps CPU comme une chaine # moyenne si plusieurs repetitions d'un meme cas unitaire #============================================================================== -def extractCPUTimeWindows(output1, output2, nreps=1): +def extractCPUTimeWindows(output1, output2): CPUtime = 'Unknown' try: split1 = output1.split(':') @@ -567,7 +567,7 @@ def extractCPUTimeWindows(output1, output2, nreps=1): ms2 = int(s2[1]) s2 = int(s2[0]) t2 = h2*3600. + m2*60. + s2 + 0.01*ms2 - tf = (t2-t1)/float(nreps) + tf = (t2-t1) hf = int(tf/3600.) tf = tf - 3600*hf mf = int(tf/60.) @@ -582,7 +582,7 @@ def extractCPUTimeWindows(output1, output2, nreps=1): # Extrait le temps CPU d'une sortie time -p (unix) # Moyenne si plusieurs repetitions d'un meme cas unitaire #============================================================================= -def extractCPUTimeUnix(output, nreps=1): +def extractCPUTimeUnix(output): CPUtime = 'Unknown' try: i1 = output.find('real') @@ -603,7 +603,6 @@ def extractCPUTimeUnix(output, nreps=1): tf = 0. for i in range(len(output)): tf += dt[i]*float(output[i]) - tf /= float(nreps) hf = tf//3600 tf = tf%3600 output = [int(hf), int(tf//60), float(tf%60)] @@ -626,7 +625,6 @@ def runSingleUnitaryTest(no, module, test): m1 = expTest1.search(test) # seq (True) ou distribue (False) nthreads = KCore.kcore.getOmpMaxThreads() - nreps = Repeats.get() bktest = "bk_{0}".format(test) # backup if mySystem == 'mingw' or mySystem == 'windows': @@ -639,24 +637,13 @@ def runSingleUnitaryTest(no, module, test): else: # Unix - le shell doit avoir l'environnement cassiopee #sformat = r'"real\t%E\nuser\t%U\nsys\t%S"' - cmdReps = "" - if nreps > 1: - cmdCmpiImport = 'import Converter.Mpi as Cmpi' - cmdCmpiTrace = 'Cmpi.trace(">>> Iteration: ", cpu=False, stdout=False, fileName="proc_{0}.txt")'.format(test[:-3]) - cmdConverterImport = 'import Converter.PyTree as CP' - cmdInitGlobalDicts = 'CP.__ZoneNameServer__ = {}; CP.__BCNameServer__ = {}; CP.__BaseNameServer__ = {}' - cmdReps = r"""rm -f proc_{7}???.txt tmp_{0}; cp {0} {6}; sed -i 's/^/ /' {0}; - sed -i '1i\{1}\\nfor _ in range({5}):' {0}; sed -i '$a\ {2}\\n {3}\\n {4}' {0};""".format( - test, cmdCmpiImport, cmdCmpiTrace, cmdConverterImport, - cmdInitGlobalDicts, nreps, bktest, test[:-3]) - sanitizerFlag = '-s' if any(USE_ASAN) else '' if m1 is None: - cmd = 'cd %s; %s time kpython %s -n 2 -t %d %s'%( - path, cmdReps, sanitizerFlag, nthreads//2, test) + cmd = 'cd %s; time kpython %s -n 2 -t %d %s'%( + path, sanitizerFlag, nthreads//2, test) else: - cmd = 'cd %s; %s time kpython %s -t %d %s'%( - path, cmdReps, sanitizerFlag, nthreads, test) + cmd = 'cd %s; time kpython %s -t %d %s'%( + path, sanitizerFlag, nthreads, test) try: if mySystem == 'mingw' or mySystem == 'windows': @@ -673,33 +660,19 @@ def runSingleUnitaryTest(no, module, test): # Recupere success/failed success = 1 + if regFailedLSAN.search(output) is not None: success = -1 # always check first if regDiff.search(output) is not None: success = 0 if regFailed.search(output) is not None: success = 0 if regError.search(output) is not None: success = 0 if regErreur.search(output) is not None: success = 0 if regAbort.search(output) is not None: success = 0 if regSegmentation.search(output) is not None: success = 0 - - # Recupere l'utilisation memoire lors des runs successifs d'un meme cas - # unitaire si celui-ci est OK. Pas de check memoire sur les cas FAILED - if nreps > 1: - if success == 1: - tolMem = 0.1 - getMemCmd = "cd {0}; ls; cut -f 2 -d '[' proc_{1}000.txt | cut -f 1 -d ' ' > tmp_{2};".format(path, test[:-3], test) - _ = check_output(getMemCmd, shell=True, stderr=subprocess.STDOUT) - memData = np.loadtxt("{0}/tmp_{1}".format(path, test)) - if memData.size > 0: - # FAILEDMEM if the delta mem if greater than a tolerance - # for each successive rerun - relDMem = np.diff(memData)/memData[:-1]*100. - print("Successive relative MEM increments (%)", relDMem) - if np.all(relDMem > tolMem): success = -1 # Recupere le CPU time if mySystem == 'mingw' or mySystem == 'windows': - CPUtime = extractCPUTimeWindows(output1, output2, nreps=nreps) + CPUtime = extractCPUTimeWindows(output1, output2) else: - CPUtime = extractCPUTimeUnix(output, nreps=nreps) + CPUtime = extractCPUTimeUnix(output) # Recupere le coverage i1 = output.find('coverage=') @@ -726,12 +699,6 @@ def runSingleUnitaryTest(no, module, test): except Exception as e: print(e) success = 0; CPUtime = 'Unknown'; coverage='0%' # Core dump/error - - finally: - if nreps > 1 and not (mySystem == 'mingw' or mySystem == 'windows'): - cleanCmd = "cd {0}; mv {1} {2}; rm -f tmp_{2} proc_{3}*.txt;".format( - path, bktest, test, test[:-3]) - _ = check_output(cleanCmd, shell=True, stderr=subprocess.STDOUT) # update le fichier .time (si non present) fileTime = '%s/%s/%s/%s/%s.time'%(MODULESDIR['LOCAL'][module], module, 'test', DATA, testr[0]) @@ -938,13 +905,8 @@ def updateTests(): pathl = os.path.join(modulesDir, module, 'test') rmFile(pathl, test) rmFile(pathl, test2) - # Set le nombre de fois qu'un cas unitaire doit etre execute a 1 - nreps = Repeats.get() - Repeats.set(1) # Run les tests runTests() - # Reset le nombre de fois qu'un cas unitaire doit etre execute a sa valeur initiale - Repeats.set(nreps) def updateTestsInThread(): global THREAD @@ -1413,23 +1375,6 @@ def displayProgress(current, total, remaining, elapsed): (current,total,time2String(remaining),time2String(elapsed))) ProgressLabel.update() -#============================================================================== -# Modifie le nbre de fois qu'un test unitaire doit etre execute. -# De multiples repetitions permettent de detecter d'eventuelles fuites memoire -#============================================================================== -def setNRepeats(event=None): - if mySystem == 'mingw' or mySystem == 'windows': - # Feature not implemented for non-Unix OS - Repeats.set(1) - else: - nr = Repeats.get() - try: - nri = int(nr) - print('Info: Number of times each test gets executed set to %d.\n'%nri) - except: - Repeats.set(1) - print('Info: Bad unit test repetition number.\n') - #============================================================================== # Modifie le nbre de threads utilises pour la valid #============================================================================== @@ -1724,6 +1669,7 @@ def updateASANOptions(): os.environ["ASAN_OPTIONS"] = "{}detect_leaks={:d}{}".format( asan_opt[:posArg], USE_ASAN[1], asan_opt[posArg+14:]) print("Info: ASAN_OPTIONS = " + os.getenv("ASAN_OPTIONS", "")) + print(" LSAN_OPTIONS = " + os.getenv("LSAN_OPTIONS", "")) def updateASANLabel(entry_index): if not INTERACTIVE: return @@ -1886,15 +1832,7 @@ def updateASANLabel(entry_index): TextThreads.bind('', setThreads) TextThreads.bind('', setThreads) getThreads() - - Repeats = TK.IntVar(Master, value=1) - RepeatsEntry = TK.Entry(Frame, textvariable=Repeats, background='White', - width=3) - if mySystem == 'windows' or mySystem == 'mingw': - RepeatsEntry["state"] = "disabled" - RepeatsEntry.grid(row=1, column=10, sticky=TK.EW) - RepeatsEntry.bind('', setNRepeats) - RepeatsEntry.bind('', setNRepeats) + Frame.grid(sticky=TK.NSEW) CTK.infoBulle(parent=TextFilter, text=filterInfoBulle) @@ -1902,8 +1840,6 @@ def updateASANLabel(entry_index): CTK.infoBulle(parent=UpdateButton, text='Update tests (replace data base files).') CTK.infoBulle(parent=TextThreads, text='Number of threads.') - CTK.infoBulle(parent=RepeatsEntry, - text='Number of times each unit test gets executed.') setupLocal() TK.mainloop() else: @@ -1923,9 +1859,6 @@ def updateASANLabel(entry_index): Threads = NoDisplayStringVar() TextThreads = NoDisplayEntry() getThreads() - - Repeats = NoDisplayIntVar(value=1) - RepeatsEntry = NoDisplayEntry() if os.access('/stck/cassiope/git/Cassiopee/', os.R_OK) and vcargs.global_db: setupGlobal(loadSession=vcargs.loadSession) diff --git a/Cassiopee/Envs/sh_Cassiopee_local b/Cassiopee/Envs/sh_Cassiopee_local index 98634eb58..f857b44f0 100644 --- a/Cassiopee/Envs/sh_Cassiopee_local +++ b/Cassiopee/Envs/sh_Cassiopee_local @@ -120,6 +120,7 @@ elif [ "$MAC" = "ld" ]; then ncpu=$((ncpu + 1)) export OMP_NUM_THREADS=$ncpu export ASAN_OPTIONS=verify_asan_link_order=false + export LSAN_OPTIONS=suppressions=$CASSIOPEE/Dist/bin/"$ELSAPROD"/asan.supp:print_suppressions=0 export ASAN_LIB=/opt/tools/gcc/10.2.0-gnu831/lib64/libasan.so elif [ "$MAC" = "ld_python2" ]; then @@ -607,6 +608,7 @@ elif [ "$MAC" = "juno_gcc" ]; then unset $(env | grep SLURM | cut -d'=' -f 1) unset OMP_PLACES export ASAN_OPTIONS=verify_asan_link_order=false + export LSAN_OPTIONS=suppressions=$CASSIOPEE/Dist/bin/"$ELSAPROD"/asan.supp:print_suppressions=0 export ASAN_LIB=/opt/tools/gcc/12.1.0-gnu831/lib64/libasan.so elif [ "$MAC" = "juno_gpu" ]; then diff --git a/Cassiopee/KCore/install b/Cassiopee/KCore/install index 64edbd630..6f547dc34 100755 --- a/Cassiopee/KCore/install +++ b/Cassiopee/KCore/install @@ -96,5 +96,13 @@ cp test/notifyValid "$INSTALLPATH" cp test/compareSessionLogs.py "$INSTALLPATH" cp test/compareSessionLogs "$INSTALLPATH" +# LSAN: Ajoute un fichier pour supprimer certaines fuites memoire du log +cat > "$INSTALLPATH"/asan.supp < Date: Thu, 5 Sep 2024 15:56:11 +0200 Subject: [PATCH 2/3] CPlot: update getActivePointIndex, MapEdge: update local refinement for CAD --- Cassiopee/CPlot/CPlot/Plugins/mouseClick.cpp | 60 +++++--- Cassiopee/CPlot/CPlot/get.cpp | 34 ++++- Cassiopee/CPlot/apps/tkMapEdge.py | 150 ++++++++++++++++++- Cassiopee/Geom/Geom/MapEdge.py | 17 ++- Cassiopee/Intersector/test/closeCells.py | 5 +- Cassiopee/Intersector/test/closeCells_t1.py | 5 +- 6 files changed, 227 insertions(+), 44 deletions(-) diff --git a/Cassiopee/CPlot/CPlot/Plugins/mouseClick.cpp b/Cassiopee/CPlot/CPlot/Plugins/mouseClick.cpp index 390d6d237..93818e2b2 100644 --- a/Cassiopee/CPlot/CPlot/Plugins/mouseClick.cpp +++ b/Cassiopee/CPlot/CPlot/Plugins/mouseClick.cpp @@ -267,55 +267,71 @@ E_Int Data::findBlockContaining(double x, double y, double z, double xmi, ymi, zmi, xma, yma, zma; double d, dn, de; E_Int nzmin = -1; - double dmin = 1.e6; // distMin node/element - double dminNode = 1.e6; // distMin node - double dminElt = 1.e6; // distMin element + double dmin = K_CONST::E_MAX_FLOAT; // distMin node/element + double dminNode = K_CONST::E_MAX_FLOAT; // distMin node + double dminElt = K_CONST::E_MAX_FLOAT; // distMin element ind = 0; indE = 0; double eps = 0.05; d = MAX(xmax-xmin, ymax-ymin); d = MAX(d, zmax-zmin); eps = d*eps; - //printf("eps: %f\n", eps); ncon = 0; for (nz = 0; nz < _numberOfZones; nz++) { - Zone* zone = _zones[nz]; - if (zone->active == 1 || - (zone->active == 0 && ptrState->ghostifyDeactivatedZones == 1)) + Zone* zonep = _zones[nz]; + if (zonep->active == 1 || + (zonep->active == 0 && ptrState->ghostifyDeactivatedZones == 1)) { - xma = zone->xmax + eps; - xmi = zone->xmin - eps; - yma = zone->ymax + eps; - ymi = zone->ymin - eps; - zma = zone->zmax + eps; - zmi = zone->zmin - eps; - //printf("try: zone %f %f %f %f %f %f\n", xmi, xma, ymi, yma, zmi, zma); + xma = zonep->xmax + eps; + xmi = zonep->xmin - eps; + yma = zonep->ymax + eps; + ymi = zonep->ymin - eps; + zma = zonep->zmax + eps; + zmi = zonep->zmin - eps; if (x >= xmi && x <= xma && y >= ymi && y <= yma && z >= zmi && z <= zma) { if (nz < _numberOfStructZones) { - findNearestPoint(x, y, z, (StructZone*)zone, indl, dn); - inde = findElement(x, y, z, (StructZone*)zone, de); + findNearestPoint(x, y, z, (StructZone*)zonep, indl, dn); + inde = findElement(x, y, z, (StructZone*)zonep, de); } else { - findNearestPoint(x, y, z, (UnstructZone*)zone, indl, dn); - inde = findElement(x, y, z, (UnstructZone*)zone, de, ncon); + findNearestPoint(x, y, z, (UnstructZone*)zonep, indl, dn); + inde = findElement(x, y, z, (UnstructZone*)zonep, de, ncon); } d = MIN(dn, de); - if (zone->active == 0) d = d + eps*0.01; // malus + if (zonep->active == 0) d = d + eps*0.01; // malus - if (d < dmin-1.e-10) + if (d < dmin-1.e-10) // node ou centre plus proche { dmin = d; nzmin = nz; ind = indl; indE = inde; dminElt = de; dminNode = dn; } - else if (d <= dmin) // meme point mini: compare dn ou de + else if (d <= dmin+1.e-10) // meme point mini: compare dn ou de { - if (de < dminElt && _zones[nzmin]->dim != 1) + if (zonep->dim == 1 && _zones[nzmin]->dim == 1) + { + if (de < dminElt) + { + dmin = d; nzmin = nz; ind = indl; indE = inde; + dminElt = de; dminNode = dn; + } + else if (dn < dminNode) + { + dmin = d; nzmin = nz; ind = indl; indE = inde; + dminElt = de; dminNode = dn; + } + } + else if (zonep->dim == 1 && _zones[nzmin]->dim != 1) + { + dmin = d; nzmin = nz; ind = indl; indE = inde; + dminElt = de; dminNode = dn; + } + else if (de < dminElt && _zones[nzmin]->dim != 1) { dmin = d; nzmin = nz; ind = indl; indE = inde; dminElt = de; dminNode = dn; diff --git a/Cassiopee/CPlot/CPlot/get.cpp b/Cassiopee/CPlot/CPlot/get.cpp index 267e61310..cc8dc9df5 100644 --- a/Cassiopee/CPlot/CPlot/get.cpp +++ b/Cassiopee/CPlot/CPlot/get.cpp @@ -19,8 +19,16 @@ #include "cplot.h" #include "Data.h" -int findFace(double xp, double yp, double zp, E_Int elt, - UnstructZone* zone, double& dist); +E_Int findNearestPoint(double xp, double yp, double zp, + StructZone* zone, E_Int& ind, double& dist); +E_Int findNearestPoint(double xp, double yp, double zp, + UnstructZone* zone, E_Int& ind, double& dist); +E_Int findElement(double xp, double yp, double zp, + UnstructZone* zone, double& dist, E_Int& ncon); +E_Int findElement(double xp, double yp, double zp, + StructZone* zone, double& dist); +E_Int findFace(double xp, double yp, double zp, E_Int elt, + UnstructZone* zone, double& dist); //====================================================== // Get mode from PyObject, return an int (0: mesh, 1: solid, @@ -390,15 +398,31 @@ PyObject* K_CPLOT::getActivePointIndex(PyObject* self, PyObject* args) if (nz == 0) return l; else { - // Re-check (if zone has been replaced) double posX, posY, posZ; E_Int zone, ind, indE, ncon; double dist; posX = d->ptrState->activePointX; posY = d->ptrState->activePointY; posZ = d->ptrState->activePointZ; - d->findBlockContaining(posX, posY, posZ, - zone, ind, indE, dist, ncon); + + // recompute zone and index + //d->findBlockContaining(posX, posY, posZ, + // zone, ind, indE, dist, ncon); + + // only recompute index + double dn, de; + zone = d->ptrState->selectedZone-1; Zone* z = d->_zones[zone]; + if (zone < d->_numberOfStructZones) + { + findNearestPoint(posX, posY, posZ, (StructZone*)z, ind, dn); + indE = findElement(posX, posY, posZ, (StructZone*)z, de); + } + else + { + findNearestPoint(posX, posY, posZ, (UnstructZone*)z, ind, dn); + indE = findElement(posX, posY, posZ, (UnstructZone*)z, de, ncon); + } + if (zone < d->_numberOfStructZones) { StructZone* zz = (StructZone*)z; diff --git a/Cassiopee/CPlot/apps/tkMapEdge.py b/Cassiopee/CPlot/apps/tkMapEdge.py index 00cd8505c..ee8ea175e 100644 --- a/Cassiopee/CPlot/apps/tkMapEdge.py +++ b/Cassiopee/CPlot/apps/tkMapEdge.py @@ -117,11 +117,11 @@ def setEnforce(event=None): nob = CTK.Nb[nz]+1 noz = CTK.Nz[nz] z = CTK.t[2][nob][2][noz] - setEnforceZ(z) + h = CTK.varsFromWidget(VARS[1].get(), 1) + setEnforceZ(z, h, VARS[8].get()) # Perform a setH on z with clicked point -def setEnforceZ(z): - h = CTK.varsFromWidget(VARS[1].get(), 1) +def setEnforceZ(z, h, mode): if len(h) != 1: CTK.TXT.insert('START', 'Invalid spacing.\n') CTK.TXT.insert('START', 'Error: ', 'Error') @@ -131,7 +131,7 @@ def setEnforceZ(z): ind = CPlot.getActivePointIndex() if ind == []: return True ind = ind[0] - if VARS[8].get() == 'HFactor': + if mode == 'HFactor': P0 = C.getValue(z, 'GridCoordinates', ind) if ind == npts-1: P1 = C.getValue(z, 'GridCoordinates', ind-1) else: P1 = C.getValue(z, 'GridCoordinates', ind+1) @@ -166,7 +166,7 @@ def setEnforceMode(event=None): nob = CTK.Nb[nz]+1 noz = CTK.Nz[nz] z = CTK.t[2][nob][2][noz] - setEnforceZ(z) + setEnforceZ(z, CTK.varsFromWidget(VARS[1].get(), 1), VARS[8].get()) CTK.__BUSY__ = False TTK.raiseButton(W) @@ -1061,6 +1061,7 @@ def copyDistrib(): CTK.setCursor(0, WIDGETS['frame']) +#============================================================================== # get selection from CTK.t def getSelection(nzs): zones = [] @@ -1070,7 +1071,9 @@ def getSelection(nzs): zones.append(CTK.t[2][nob][2][noz]) return zones +#============================================================================== # remesh CAD when an edge is modified +#============================================================================== def remeshCAD(edges): try: import OCC.PyTree as OCC except: return @@ -1088,7 +1091,125 @@ def remeshCAD(edges): [h,hmax,hausd] = CTK.CADHOOK OCC._remeshTreeFromEdges(h, CTK.t, valids) CTK.display(CTK.t) + +#============================================================================== +# enforce h in edge locally +#============================================================================== +def enforceLocal(event=None): + v = CTK.varsFromWidget(VARS[12].get(), 1) + if len(v) != 1: + CTK.TXT.insert('START', 'Invalid h or hfactor.\n') + CTK.TXT.insert('START', 'Error: ', 'Error') + return + v = v[0] + width = WIDGETS['widthScale'].get() / 100. + width = max(width, 0.1) + mode = VARS[11].get() + + # get edge + nzs = CPlot.getSelectedZones() + nz = nzs[0] + nob = CTK.Nb[nz]+1 + noz = CTK.Nz[nz] + z = CTK.t[2][nob][2][noz] + dim = Internal.getZoneDim(z) + if dim[4] != 1: + CTK.TXT.insert('START', 'Zone must be an edge.\n') + CTK.TXT.insert('START', 'Error: ', 'Error') + return + npts = C.getNPts(z) + + CTK.saveTree() + CPlot.setState(cursor=1) + # split zone of width + ind = CPlot.getActivePointIndex() + if ind == []: return + ind = ind[0] + + P0 = C.getValue(z, 'GridCoordinates', ind) + if ind == npts-1: P1 = C.getValue(z, 'GridCoordinates', ind-1) + else: P1 = C.getValue(z, 'GridCoordinates', ind+1) + hloc = Vector.norm(Vector.sub(P1,P0)) + if mode == 'HFactor': + h = v*hloc; factor = v + else: h = v; factor = h / hloc + + delta = int(width*npts)+1 + imin = ind+1-delta + imax = ind+1+delta + + CAD = Internal.getNodeFromName1(z, 'CAD') + + if imin > 1: z0 = T.subzone(z, (1,1,1), (imin,-1,-1)) + else: z0 = None + if ind > 2: zp1 = T.subzone(z, (max(imin,1),1,1), (ind+1,-1,-1)) + else: zp1 = None + if ind < npts-1: zp2 = T.subzone(z, (ind+1,1,1), (min(imax, npts),-1,-1)) + else: zp2 = None + if imax < npts: z1 = T.subzone(z, (imax,1,1), (npts,-1,-1)) + else: z1 = None + + if zp1 is not None: + P0 = C.getValue(zp1, 'GridCoordinates', 0) + P1 = C.getValue(zp1, 'GridCoordinates', 1) + h1 = Vector.norm(Vector.sub(P1,P0)) + L = D.getLength(zp1) + if h+h1 > L: h1 = h + + if zp2 is not None: + P0 = C.getValue(zp2, 'GridCoordinates', -1) + P1 = C.getValue(zp2, 'GridCoordinates', -2) + h2 = Vector.norm(Vector.sub(P1,P0)) + L = D.getLength(zp2) + if h+h2 > L: h2 = h + + if zp1 is None: h1 = h2 + if zp2 is None: h2 = h1 + + #if z0 is None: h1 = (h1+h)*0.5 + #if z1 is None: h2 = (h2+h)*0.5 + + # D._setH(zp, ind-imin+1, h) + # # guess a cool number of points + # if factor == 1.: + # N = npts + # elif factor < 1.: + # N = npts + (1./factor)/100.*npts + # N = int(N)+1 + # else: + # N = npts - (1./factor)/100.*npts + # N = int(N)+1 + # print("nbre de points=", N) + # D._enforceh(zp, N=N) + + if zp1 is not None: + d2 = D.distrib2(zp1, h1, h, algo=1) + zp1 = G.map(zp1, d2) + if zp2 is not None: + d2 = D.distrib2(zp2, h, h2, algo=1) + zp2 = G.map(zp2, d2) + + zo = None + if zp1 is not None: zo = zp1 + if zp2 is not None: + if zo is not None: zo = T.join(zo, zp2) + else: zo = zp2 + if z0 is not None: zo = T.join(z0, zo) + if z1 is not None: zo = T.join(zo, z1) + zo[0] = z[0] # keep orig name and CAD + zo[2].append(CAD) + + CTK.replace(CTK.t, nob, noz, zo) + (CTK.Nb, CTK.Nz) = CPlot.updateCPlotNumbering(CTK.t) + CTK.TKTREE.updateApp() + CPlot.render() + CTK.TXT.insert('START', 'Local spacing enforced.\n') + + # add CAD remesh if possible + edges = getSelection(nzs) + remeshCAD(edges) + CPlot.setState(cursor=0) #============================================================================== # Create app widgets @@ -1145,6 +1266,10 @@ def createApp(win): V = TK.StringVar(win); V.set('NFactor'); VARS.append(V) # -10- Nbre de pts pour h enforce V = TK.StringVar(win); V.set('1.'); VARS.append(V) + # -11- Type of local enforce + V = TK.StringVar(win); V.set('HFactor'); VARS.append(V) + # -12- Factor for local enforce + V = TK.StringVar(win); V.set('1.'); VARS.append(V) # - Uniformize - B = TTK.Button(Frame, text="Uniformize", command=uniformize) @@ -1217,6 +1342,21 @@ def createApp(win): B.grid(row=5, column=2, columnspan=2, sticky=TK.EW) BB = CTK.infoBulle(parent=B, text='Enforced number of points.') B.bind('', enforceH) + + # - Enforce local - + B = TTK.Button(Frame, text="Enforce", command=enforceLocal) + B.grid(row=6, column=0, columnspan=1, sticky=TK.EW) + BB = CTK.infoBulle(parent=B, text='Enforce local spacing.') + B = TTK.OptionMenu(Frame, VARS[11], 'HFactor', 'H') + B.grid(row=6, column=1, sticky=TK.EW) + B = TTK.Entry(Frame, textvariable=VARS[12], background='White', width=7) + B.grid(row=6, column=2, columnspan=1, sticky=TK.EW) + BB = CTK.infoBulle(parent=B, text='Enforced variable.') + B.bind('', enforceLocal) + B = TTK.Scale(Frame, from_=0, to=100, orient=TK.HORIZONTAL, + showvalue=0, borderwidth=1, value=50) + WIDGETS['widthScale'] = B + B.grid(row=6, column=3, sticky=TK.EW) #============================================================================== # Called to display widgets diff --git a/Cassiopee/Geom/Geom/MapEdge.py b/Cassiopee/Geom/Geom/MapEdge.py index 753c406f3..2132adbb9 100644 --- a/Cassiopee/Geom/Geom/MapEdge.py +++ b/Cassiopee/Geom/Geom/MapEdge.py @@ -432,12 +432,17 @@ def distrib2(a, h1, h2, add=20, forceAdd=False, normalized=True, algo=0, verbose if normalized: a = D.getDistribution(a) return a else: # geometrique - q = (L-h1)/(L-h2) - if verbose > 0: print("Info: distrib2: geometric progression: %g"%q) - N = numpy.log(h2/h1) / numpy.log(q) - N = int(T.kround(N))+2 - if N <= 2: print('Error: distrib2: not enough point to remesh.') - a = G.cartr1((0,0,0), (h1,1,1), (q,1,1), (N,1,1)) + if abs(h2-h1) < 1.e-6: # constant step + N = int(T.kround(L / h1)) + h = L/N + a = G.cart((0,0,0), (h,1,1), (N,1,1)) + else: + q = (L-h1)/(L-h2) + if verbose > 0: print("Info: distrib2: geometric progression: %g"%q) + N = numpy.log(h2/h1) / numpy.log(q) + N = int(T.kround(N))+2 + if N <= 2: print('Error: distrib2: not enough point to remesh.') + a = G.cartr1((0,0,0), (h1,1,1), (q,1,1), (N,1,1)) if normalized: a = D.getDistribution(a) return a diff --git a/Cassiopee/Intersector/test/closeCells.py b/Cassiopee/Intersector/test/closeCells.py index 61fa2db42..2d381556b 100644 --- a/Cassiopee/Intersector/test/closeCells.py +++ b/Cassiopee/Intersector/test/closeCells.py @@ -1,4 +1,4 @@ -# - triangulateExteriorFaces (array) - +# - closeCells (array) - import Intersector as XOR import Converter as C @@ -6,5 +6,4 @@ m = C.convertArray2NGon(m[0]) m = XOR.closeCells(m) -C.convertArrays2File([m], 'out.plt') - +C.convertArrays2File([m], 'out.plt') \ No newline at end of file diff --git a/Cassiopee/Intersector/test/closeCells_t1.py b/Cassiopee/Intersector/test/closeCells_t1.py index 974f7003a..9550f3aec 100644 --- a/Cassiopee/Intersector/test/closeCells_t1.py +++ b/Cassiopee/Intersector/test/closeCells_t1.py @@ -1,4 +1,4 @@ -# - triangulateExteriorFaces (array) - +# - closeCells (array) - import Intersector as XOR import Converter as C import KCore.test as test @@ -8,5 +8,4 @@ m = XOR.closeCells(m) -test.testA([m],1) - +test.testA([m],1) \ No newline at end of file From 9c655dd3950416e168051c03d18914ad3e2ae921 Mon Sep 17 00:00:00 2001 From: benoit128 Date: Thu, 5 Sep 2024 16:18:30 +0200 Subject: [PATCH 3/3] docker: update account --- .github/workflows/build-docker.yml | 2 +- docs/developers/Docker/UsingDocker.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index c1b7f953a..7731342af 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -33,5 +33,5 @@ jobs: with: context: . push: true - tags: hystrath/cassiopee:${{ github.ref_name }} + tags: cassiopee486/cassiopee:${{ github.ref_name }} diff --git a/docs/developers/Docker/UsingDocker.md b/docs/developers/Docker/UsingDocker.md index 5f61491fd..5f6456e3e 100644 --- a/docs/developers/Docker/UsingDocker.md +++ b/docs/developers/Docker/UsingDocker.md @@ -30,7 +30,7 @@ groups ${USER} - Please pull the official image of Cassiopee from DockerHub ```sh -docker pull cassiopee/cassiopee: +docker pull cassiopee486/cassiopee: ``` where _tag_ is a version tag such as `v4.0b` (in the remainder of these notes, `v4.0b` is used). @@ -50,7 +50,7 @@ docker images ```sh xhost +local:docker -docker run -it --rm -v /tmp/.X11-unix:/tmp/.X11-unix -v /dev/dri:/dev/dri -e DISPLAY=unix$DISPLAY cassiopee/cassiopee:v4.0b +docker run -it --rm -v /tmp/.X11-unix:/tmp/.X11-unix -v /dev/dri:/dev/dri -e DISPLAY=unix$DISPLAY cassiopee486/cassiopee:v4.0b ``` and the instance of the container will be removed after it execution thanks to `--rm`.