Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merging main to dev #247

Merged
merged 8 commits into from
Dec 24, 2024
11 changes: 7 additions & 4 deletions Cassiopee/CPlot/apps/validCassiopee.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ def _setModuleDirs(cassiopeeIncDir, fastIncDir, pmodulesIncDir, loc='LOCAL'):

# Module paths when the global base is used
parentDirname = os.path.join('/stck', 'cassiope', 'git')
if os.access(parentDirname, os.R_OK):
if getDBInfo(): # check if a global base exists
cassiopeeIncDir = os.path.join(parentDirname, 'Cassiopee', 'Cassiopee')
fastIncDir = os.path.join(parentDirname, 'Fast', 'Fast')
if not os.path.isdir(fastIncDir): fastIncDir = None
Expand Down Expand Up @@ -1582,10 +1582,11 @@ def setupLocal(**kwargs):
createEmptySessionLog()
buildTestList(**kwargs)
updateDBLabel()
return 0

def setupGlobal(**kwargs):
global BASE4COMPARE
if VALIDDIR['GLOBAL'] is None: return
if VALIDDIR['GLOBAL'] is None: return 1
# Change to global ref
print('Info: comparing to global database.')
BASE4COMPARE = 'GLOBAL'
Expand All @@ -1603,6 +1604,7 @@ def setupGlobal(**kwargs):
createEmptySessionLog()
buildTestList(**kwargs)
updateDBLabel()
return 0

def getDBInfo():
dbInfo = ''
Expand All @@ -1622,7 +1624,7 @@ def updateDBLabel():
if BASE4COMPARE == 'GLOBAL':
label = 'Switch to local data base'
else:
label = 'Switch to global data base ' + getDBInfo()
label = 'Switch to global data base ' + dbInfo
toolsTab.entryconfig(3, label=label)

#==============================================================================
Expand Down Expand Up @@ -1873,7 +1875,8 @@ def updateASANLabel(entry_index):
CTK.infoBulle(parent=UpdateButton,
text='Update tests (replace data base files).')
CTK.infoBulle(parent=TextThreads, text='Number of threads.')
setupLocal()
ierr = setupGlobal() # Comparison is made against the global valid
if ierr == 1: setupLocal() # Global valid does not exist, default back to local
TK.mainloop()
else:
# --- Command line execution ---
Expand Down
26 changes: 19 additions & 7 deletions Cassiopee/Converter/Converter/kpython
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ NTHREADS="0"
ARGS=""
# SANITIZE (-s)
SANITIZE="0"
# GDB (-g)
GDB="0"

while getopts :hpsn:t:a: OPTION
while getopts :hpsgn:t:a: OPTION
do
case $OPTION in
h)
Expand Down Expand Up @@ -81,7 +83,9 @@ do
s)
SANITIZE="1"
;;

g)
GDB="1"
;;
\?)
PYARGS+=$OPTARG
;;
Expand Down Expand Up @@ -128,20 +132,28 @@ fi
echo 'Running '$SCRIPT' with Nprocs='$NPROCS' and Nthreads='$NTHREADS

if [ "$NPROCS" = "0" ]
then
then # sequential run forced
export MPIRUN=0
export OMP_NUM_THREADS=$NTHREADS
if [ $SANITIZE = '1' ]
if [ $SANITIZE = '1' -a $GDB = '0' ]
then
export LD_PRELOAD=$ASAN_LIB
$PYTHONEXE $ARGS $SCRIPT
unset LD_PRELOAD
elif [ $SANITIZE = '1' -a $GDB = '1' ]
then
export LD_PRELOAD=$ASAN_LIB
gdb --args $PYTHONEXE $ARGS $SCRIPT
unset LD_PRELOAD
elif [ $SANITIZE = '0' -a $GDB = '1' ]
then
gdb --args $PYTHONEXE $ARGS $SCRIPT #--eval-command="r "$SCRIPT
else
$PYTHONEXE $ARGS $SCRIPT
fi
export OMP_NUM_THREADS=$OMPNUMTHREADSINIT
unset MPIRUN
else
else # parallel run forced
export MPIRUN=1
export OMP_NUM_THREADS=$NTHREADS
case "$ELSAPROD" in
Expand Down Expand Up @@ -204,9 +216,9 @@ else
# openMpi
if [ $SANITIZE = '1' ]
then
mpirun $ARGS -x LD_PRELOAD=$ASAN_LIB -x OMP_NUM_THREADS=$NTHREADS -np $NPROCS -x OMP_PLACES=cores $PYTHONEXE $SCRIPT #--bind-to core --map-by socket:PE=$NTHREADS --report-bindings -x OMP_PROC_BIND=TRUE -x OMP_DISPLAY_ENV=VERBOSE
mpirun $ARGS -x LD_PRELOAD=$ASAN_LIB -x OMP_NUM_THREADS=$NTHREADS -np $NPROCS --bind-to core --map-by socket:PE=$NTHREADS $PYTHONEXE $SCRIPT #--report-bindings
else
mpirun $ARGS -x OMP_NUM_THREADS=$NTHREADS -np $NPROCS -x OMP_PLACES=cores $PYTHONEXE $SCRIPT #--bind-to core --map-by socket:PE=$NTHREADS --report-bindings -x OMP_PROC_BIND=TRUE -x OMP_DISPLAY_ENV=VERBOSE
mpirun $ARGS -x OMP_NUM_THREADS=$NTHREADS -np $NPROCS --bind-to core --map-by socket:PE=$NTHREADS $PYTHONEXE $SCRIPT #--report-bindings
fi
[ $? != 0 ] && exit 1;
;;
Expand Down
7 changes: 5 additions & 2 deletions Cassiopee/Envs/sh_Cassiopee_local
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ elif [ "$MAC" = "juno_coda" ]; then
export OMP_NUM_THREADS=48
# modules
module purge
source /stck/rhea/dist/juno_v2024_02_python3108/source.sh --env coda_dev --compiler gcc@10 --mpi openmpi
source /stck/rhea/dist/juno_v2024_08/source.sh --env coda_users
module load lapack/3.9.1-gnu831
module load occt/7.6.1-gnu831
module load subversion/1.14.1-gnu831
Expand All @@ -645,7 +645,10 @@ elif [ "$MAC" = "juno_coda" ]; then
export PRODMODE=1
export PIP_DISABLE_PIP_VERSION_CHECK=1
unset $(env | grep SLURM | cut -d'=' -f 1)
unset OMP_PLACES
#unset OMP_PLACES
export OMP_PLACES=cores
export OMP_PROC_BIND=TRUE
#export OMP_DISPLAY_ENV=VERBOSE
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
Expand Down
2 changes: 1 addition & 1 deletion Cassiopee/Generator/Generator/Generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -1466,7 +1466,7 @@ def T3mesher2D(a, grading=1.2, triangulateOnly=0, metricInterpType=0):
except:
return generator.T3mesher2D(a, grading, triangulateOnly, metricInterpType)

def tetraMesher(a, maxh=-1., grading=0.4,
def tetraMesher(a, maxh=-1., grading=0.4, triangulateOnly=0,
remeshBoundaries=0, algo=1, optionString=""):
"""Create a TRI/TETRA mesh given a set of BAR or surfaces in a.
Usage: tetraMesher(a, maxh, grading)"""
Expand Down
12 changes: 6 additions & 6 deletions Cassiopee/KCore/KCore/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,8 @@ def checkTree__(node1, node2):
if isinstance(val1, str):
if not isinstance(val2, str):
print('DIFF: types de valeurs differents pour le noeud: %s.'%node1[0])
print('DIFF: reference:'+val2)
print('DIFF: courant:'+val1)
print('DIFF: reference: {}'.format(type(val2)))
print('DIFF: courant: str')
return 0
if val1 != val2:
print('DIFF: valeurs differentes pour le noeud: %s.'%node1[0])
Expand All @@ -385,8 +385,8 @@ def checkTree__(node1, node2):
elif isinstance(val1, float):
if not isinstance(val2, float):
print('DIFF: types de valeurs differents pour le noeud: %s.'%node1[0])
print('DIFF: reference: %f'%val2)
print('DIFF: courant: %f'%val1)
print('DIFF: reference: {}'.format(type(val2)))
print('DIFF: courant: float')
return 0
if val1 != val2:
print('DIFF: valeurs differentes pour le noeud: %s.'%node1[0])
Expand All @@ -396,8 +396,8 @@ def checkTree__(node1, node2):
elif isinstance(val1, int):
if not isinstance(val2, int):
print('DIFF: types de valeurs differents pour le noeud: %s.'%node1[0])
print('DIFF: reference: %d'%val2)
print('DIFF: courant: %d'%val1)
print('DIFF: reference: {}'.format(type(val2)))
print('DIFF: courant: int')
return 0
if val1 != val2:
print('DIFF: valeurs differentes au noeud:'%node1[0])
Expand Down
128 changes: 128 additions & 0 deletions tools/test_scanner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Scan Cassiopee's MODULES and output in a log file all (non-internal) functions
# that are not listed in any tests of the module they were defined in.
# If a function is also available inplace, only one of these two functions needs
# to have a test.
#
# Usage:
# - run: python test_scanner.py
# - open the output file ./missingTests.txt

import os
import sys
import re

CASSIOPEE = os.path.join(os.environ.get("CASSIOPEE"), 'Cassiopee')

def findFileNames(rootDir, targets=[], patterns=[], excludeDirs=[]):
"""
Search for all files with the specified name in any subdirectory

:param rootDir: The root directory to start searching from
:param fileNames: The name of the file to search for
:return: A list of file paths matching any of the target file names
"""
matches = []
regexs = [re.compile(p) for p in patterns]

for dirpath, _, filenames in os.walk(rootDir):
if any(d in dirpath for d in excludeDirs): continue
for target in targets:
if target in filenames:
matches.append(os.path.join(dirpath, target))
for filename in filenames:
for regex in regexs:
if regex.match(filename):
matches.append(os.path.join(dirpath, filename))
return matches

def findFunctionNames(fileNames, excludePrivate=True):
def _find(fileName):
names = []
with open(fileName, 'r') as f:
for line in f:
if "def " in line:
name = line.strip()
if name[0] == '#': continue
name = name.split()[1].split('(')[0]
if excludePrivate and '__' in name: continue
names.append(name)
return names
return {fileName: _find(fileName) for fileName in fileNames}

def arePatternsFound(fileNames, patterns, include_inline=True):
def _isPatternFound(fileNames, pattern):
for fileName in fileNames:
with open(fileName, 'r') as f:
for line in f:
if pattern in line:
return True
elif include_inline and pattern[0] == "_" and pattern[1:] in line:
return True
return False
return [_isPatternFound(fileNames, pattern) for pattern in patterns]


if __name__ == "__main__":
# Read module names
with open(os.path.join(CASSIOPEE, 'MODULES'), 'r') as f:
moduleNames = f.readline().split("'")[1].split()

foundOutfile = open('foundTests.txt', 'w')
missingOutfile = open('missingTests.txt', 'w')

# Loop over all modules
for module in moduleNames:
print(f">>> Module {module}")

# Search for python source files
rootDir = os.path.join(CASSIOPEE, module)
fileNames = ["PyTree.py", f"{module}.py", "Internal.py", "Mpi.py"]
pysrc = findFileNames(
rootDir=rootDir,
targets=fileNames,
excludeDirs=['build', 'test', 'mystuff']
)
if not pysrc: continue
#print("pysrc", pysrc)

fnNames = findFunctionNames(pysrc)
#print("fnNames", fnNames)

# Search for test cases
fileNames = [r".*_[tm][0-9]*\.py"]
tests = findFileNames(
rootDir=os.path.join(rootDir, 'test'),
patterns=fileNames
)
if not tests: continue
#print("tests", tests)

foundFnNames, missingFnNames = {}, {}
for src, fns in fnNames.items():
testFound = arePatternsFound(tests, fns)
foundFnNames[src] = [fn for i, fn in enumerate(fns) if testFound[i]]
missingFnNames[src] = [fn for i, fn in enumerate(fns) if not testFound[i]]

#print("fnNames", fnNames)

# Print to file
missingOutfile.write(f"Module {module}\n")
for src, fns in missingFnNames.items():
if not missingFnNames[src]: continue
source = os.path.relpath(src, CASSIOPEE)
missingOutfile.write(f" - Source {source}\n")
missingOutfile.write("\n".join(f" + {fn}" for fn in fns))
missingOutfile.write("\n\n")
missingOutfile.write('-'*80 + "\n\n")

foundOutfile.write(f"Module {module}\n")
for src, fns in foundFnNames.items():
if not foundFnNames[src]: continue
source = os.path.relpath(src, CASSIOPEE)
foundOutfile.write(f" - Source {source}\n")
foundOutfile.write("\n".join(f" + {fn}" for fn in fns))
foundOutfile.write("\n\n")
foundOutfile.write('-'*80 + "\n\n")

missingOutfile.close()
foundOutfile.close()
Loading