From 8bc76e778c8bcb09fb7f2aff65d71d4ebf5b29eb Mon Sep 17 00:00:00 2001 From: epernod Date: Thu, 13 Jun 2024 00:48:05 +0200 Subject: [PATCH 01/28] Add new regression script fully in python --- new_regression.py | 102 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 new_regression.py diff --git a/new_regression.py b/new_regression.py new file mode 100644 index 0000000..195948c --- /dev/null +++ b/new_regression.py @@ -0,0 +1,102 @@ +import glob, os +import argparse +import sys +import Sofa + + +debugInfo = True + +class RegressionSceneData: + def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1000, + epsilon = 0.0001, mecaInMapping = True, dumpOnlyLastStep = False): + """ + /// Path to the file scene to test + std::string m_fileScenePath; + /// Path to the reference file corresponding to the scene to test + std::string m_fileRefPath; + /// Number of step to perform + unsigned int m_steps; + /// Threshold value for dof position comparison + double m_epsilon; + /// Option to test mechanicalObject in Node containing a Mapping (true will test them) + bool m_mecaInMapping; + /// Option to compare mechanicalObject dof position at each timestep + bool m_dumpOnlyLastStep; + """ + self.fileScenePath = fileScenePath + self.fileRefPath = fileRefPath + self.steps = steps + self.epsilon = epsilon + self.mecaInMapping = mecaInMapping + self.dumpOnlyLastStep = dumpOnlyLastStep + + +class RegressionSceneList: + def __init__(self, node, logGraph): + + + + +def findRegressionFiles(inputFolder): + for root, dirs, files in os.walk(inputFolder): + for file in files: + if file.endswith(".regression-tests"): + filePath = os.path.join(root, file) + + if (debugInfo): + print("Regression file found: " + filePath) + + # access header and store all includes + # with open(filePath, 'r') as thefile: + # data = thefile.readlines() + # thefile.close() + + # target = "SetTopologyAlgorithms" + + # new_file = open(filePath, "w") + + # for idx, line in enumerate(data): + # if re.search(target, line): + # continue; + + # new_file.write(line) + + # new_file.close() + + + +def parse_args(): + """ + Parse input arguments + """ + parser = argparse.ArgumentParser( + description='Regression arguments') + parser.add_argument('--input', + dest='input', + help='help input', + type=str) + + parser.add_argument('--output', + dest='output', + help="Directory where to export data preprocessed", + type=str) + + parser.add_argument( + "--classify", + dest="classify", + default=False, + help='Sort files into folders per class' + ) + + args = parser.parse_args() + + return args + + +if __name__ == '__main__': + # 1- Parse arguments to get folder path + args = parse_args() + + # 2- Process file + findRegressionFiles(args.input) + \ No newline at end of file From e3b9e3064c1426b076019b7432413dbc269296ea Mon Sep 17 00:00:00 2001 From: epernod Date: Thu, 13 Jun 2024 02:02:30 +0200 Subject: [PATCH 02/28] Add structure to store Scenedata and parse regression-test files. --- new_regression.py | 188 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 158 insertions(+), 30 deletions(-) diff --git a/new_regression.py b/new_regression.py index 195948c..dd99fd6 100644 --- a/new_regression.py +++ b/new_regression.py @@ -30,38 +30,99 @@ def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1 self.mecaInMapping = mecaInMapping self.dumpOnlyLastStep = dumpOnlyLastStep - -class RegressionSceneList: - def __init__(self, node, logGraph): - + def printInfo(self): + print("Test scene: " + self.fileScenePath + " vs " + self.fileRefPath + " using: " + self.steps + + " " + self.epsilon) - -def findRegressionFiles(inputFolder): - for root, dirs, files in os.walk(inputFolder): - for file in files: - if file.endswith(".regression-tests"): - filePath = os.path.join(root, file) - - if (debugInfo): - print("Regression file found: " + filePath) - - # access header and store all includes - # with open(filePath, 'r') as thefile: - # data = thefile.readlines() - # thefile.close() - - # target = "SetTopologyAlgorithms" - - # new_file = open(filePath, "w") - - # for idx, line in enumerate(data): - # if re.search(target, line): - # continue; +class RegressionSceneList: + def __init__(self, filePath): + self.filePath = filePath + self.fileDir = os.path.dirname(filePath) + self.scenes = [] + + def processFile(self): + print("### Processing Regression file: " + self.filePath) + with open(self.filePath, 'r') as thefile: + data = thefile.readlines() + thefile.close() + + count = 0 + for idx, line in enumerate(data): + if (line[0] == "#"): + continue + + values = line.split() + if (len(values) == 0): + continue + + if (count == 0): + print("Line ref: " + line) + self.refDirPath = line + count = count + 1 + continue + + + + if (len(values) < 4): + print ("line read has more than 5 arguments: " + str(len(values)) + " -> " + line) + continue + + fullFilePath = os.path.join(self.fileDir, values[0]) + if (len(values) == 5): + sceneData = RegressionSceneData(fullFilePath, self.refDirPath, values[1], values[2], values[3], values[4]) + elif (len(values) == 4): + sceneData = RegressionSceneData(fullFilePath, self.refDirPath, values[1], values[2], values[3], False) + + #sceneData.printInfo() + self.scenes.append(sceneData) + + print("## nbrScenes: " + str(len(self.scenes))) + # target = "SetTopologyAlgorithms" + + # new_file = open(filePath, "w") + + # for idx, line in enumerate(data): + # if re.search(target, line): + # continue; + + # new_file.write(line) + + # new_file.close() + + +class RegressionProgram: + def __init__(self, inputFolder): + self.sceneSets = [] +#def findRegressionFiles(inputFolder): + for root, dirs, files in os.walk(inputFolder): + for file in files: + if file.endswith(".regression-tests"): + filePath = os.path.join(root, file) + + sceneList = RegressionSceneList(filePath) + + sceneList.processFile() + self.sceneSets.append(sceneList) + # if (debugInfo): + # print("Regression file found: " + filePath) + + # access header and store all includes + # with open(filePath, 'r') as thefile: + # data = thefile.readlines() + # thefile.close() - # new_file.write(line) - - # new_file.close() + # target = "SetTopologyAlgorithms" + + # new_file = open(filePath, "w") + + # for idx, line in enumerate(data): + # if re.search(target, line): + # continue; + + # new_file.write(line) + + # new_file.close() @@ -98,5 +159,72 @@ def parse_args(): args = parse_args() # 2- Process file - findRegressionFiles(args.input) + prog = RegressionProgram(args.input) + + print ("### Number of sets: " + str(len(prog.sceneSets))) + + firstSet = prog.sceneSets[1] + print(firstSet.scenes[0].fileScenePath) + node = Sofa.Simulation.load(firstSet.scenes[0].fileScenePath) + + + + # if (!createReference) + # { + # // Add CompareState components: as it derives from the ReadState, we use the ReadStateActivator to enable them. + # sofa::component::playback::CompareStateCreator compareVisitor(sofa::core::ExecParams::defaultInstance()); + + # compareVisitor.setCreateInMapping(data.m_mecaInMapping); + # compareVisitor.setSceneName(data.m_fileRefPath); + # compareVisitor.execute(root.get()); + + # sofa::component::playback::ReadStateActivator v_read(sofa::core::ExecParams::defaultInstance() /* PARAMS FIRST */, true); + # v_read.execute(root.get()); + # } + # else // create reference + # { + # msg_warning("StateRegression_test::runTestImpl") << "Non existing reference created: " << data.m_fileRefPath; + + # // just to create an empty file to know it is already init + # std::ofstream filestream(data.m_fileRefPath.c_str()); + # filestream.close(); + + # sofa::component::playback::WriteStateCreator writeVisitor(sofa::core::ExecParams::defaultInstance()); + + # if (data.m_dumpOnlyLastStep) + # { + # std::vector times; + # times.push_back(0.0); + # times.push_back(root->getDt() * (data.m_steps - 1)); + # writeVisitor.setExportTimes(times); + # } + # writeVisitor.setCreateInMapping(data.m_mecaInMapping); + # writeVisitor.setSceneName(data.m_fileRefPath); + # writeVisitor.execute(root.get()); + + # sofa::component::playback::WriteStateActivator v_write(sofa::core::ExecParams::defaultInstance() /* PARAMS FIRST */, true); + # v_write.execute(root.get()); + # } + + # for (unsigned int i = 0; igetDt()); + # } + + # if (!createReference) + # { + # // Read the final error: the summation of all the error made at each time step + # sofa::component::playback::CompareStateResult result(sofa::core::ExecParams::defaultInstance()); + # result.execute(root.get()); + + # double errorByDof = result.getErrorByDof() / double(result.getNumCompareState()); + # if (errorByDof > data.m_epsilon) + # { + # msg_error("StateRegression_test::runTestImpl") + # << data.m_fileScenePath << ":" << msgendl + # << " TOTALERROR: " << result.getTotalError() << msgendl + # << " ERRORBYDOF: " << errorByDof; + # } + # } + \ No newline at end of file From f6e7a1770e5834e0815fd84ec82b74ce6a2cfdec Mon Sep 17 00:00:00 2001 From: epernod Date: Thu, 13 Jun 2024 10:58:14 +0200 Subject: [PATCH 03/28] start work on mechanicalState search --- new_regression.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/new_regression.py b/new_regression.py index dd99fd6..aed8c28 100644 --- a/new_regression.py +++ b/new_regression.py @@ -154,6 +154,18 @@ def parse_args(): return args +#def isSimulated(mstate): + + +def parseNode(node, level = 0): + for child in node.children: + print (str(level) + " -> " + child.name.value) + mstate = child.getMechanicalState() + if (mstate): + print (" -> " + mstate.name.value) + parseNode(child, level+1) + + if __name__ == '__main__': # 1- Parse arguments to get folder path args = parse_args() @@ -163,11 +175,12 @@ def parse_args(): print ("### Number of sets: " + str(len(prog.sceneSets))) - firstSet = prog.sceneSets[1] - print(firstSet.scenes[0].fileScenePath) - node = Sofa.Simulation.load(firstSet.scenes[0].fileScenePath) - - + for i in range(0, 4): + firstSet = prog.sceneSets[1] + print(firstSet.scenes[i].fileScenePath) + rootNode = Sofa.Simulation.load(firstSet.scenes[i].fileScenePath) + print("######## scene: " + str(firstSet.scenes[i].fileScenePath)) + parseNode(rootNode, 0) # if (!createReference) # { From dd2f77950d48886f9b9d15baa50beb0e92ce2c6e Mon Sep 17 00:00:00 2001 From: epernod Date: Thu, 13 Jun 2024 16:33:44 +0200 Subject: [PATCH 04/28] Add scene ref path computation --- new_regression.py | 77 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/new_regression.py b/new_regression.py index aed8c28..f18e43d 100644 --- a/new_regression.py +++ b/new_regression.py @@ -6,6 +6,19 @@ debugInfo = True +def isSimulated(node): + if (node.hasODESolver()): + return True + + # if no Solver in current node, check parent nodes + for parent in node.parents: + solverFound = isSimulated(parent) + if (solverFound): + return True + + return False + + class RegressionSceneData: def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1000, epsilon = 0.0001, mecaInMapping = True, dumpOnlyLastStep = False): @@ -29,20 +42,46 @@ def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1 self.epsilon = epsilon self.mecaInMapping = mecaInMapping self.dumpOnlyLastStep = dumpOnlyLastStep + self.mecaObjs = [] def printInfo(self): print("Test scene: " + self.fileScenePath + " vs " + self.fileRefPath + " using: " + self.steps + " " + self.epsilon) + + def printMecaObjs(self): + print ("# Nbr Meca: " + str(len(self.mecaObjs))) + counter = 0 + for mecaObj in self.mecaObjs: + filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" + + counter = counter+1 + print ("# toRead: " + filename) + + def parseNode(self, node, level = 0): + for child in node.children: + mstate = child.getMechanicalState() + if (mstate): + if (isSimulated(child)): + self.mecaObjs.append(mstate) + + self.parseNode(child, level+1) + + # def addCompareState(self): + # for mecaObj in self.mecaObjs: + # mecaObj.getContext().addObject('CompareState') + # print ("# toRead: " + mecaObj.name.value) + class RegressionSceneList: def __init__(self, filePath): self.filePath = filePath self.fileDir = os.path.dirname(filePath) - self.scenes = [] + self.scenes = [] # List def processFile(self): print("### Processing Regression file: " + self.filePath) + with open(self.filePath, 'r') as thefile: data = thefile.readlines() thefile.close() @@ -57,22 +96,24 @@ def processFile(self): continue if (count == 0): - print("Line ref: " + line) - self.refDirPath = line + print("Line ref: " + values[0]) + self.refDirPath = os.path.join(self.fileDir, values[0]) + self.refDirPath = os.path.abspath(self.refDirPath) count = count + 1 continue - if (len(values) < 4): print ("line read has more than 5 arguments: " + str(len(values)) + " -> " + line) continue fullFilePath = os.path.join(self.fileDir, values[0]) + fullRefFilePath = os.path.join(self.refDirPath, values[0]) + if (len(values) == 5): - sceneData = RegressionSceneData(fullFilePath, self.refDirPath, values[1], values[2], values[3], values[4]) + sceneData = RegressionSceneData(fullFilePath, fullRefFilePath, values[1], values[2], values[3], values[4]) elif (len(values) == 4): - sceneData = RegressionSceneData(fullFilePath, self.refDirPath, values[1], values[2], values[3], False) + sceneData = RegressionSceneData(fullFilePath, fullRefFilePath, values[1], values[2], values[3], False) #sceneData.printInfo() self.scenes.append(sceneData) @@ -93,7 +134,7 @@ def processFile(self): class RegressionProgram: def __init__(self, inputFolder): - self.sceneSets = [] + self.sceneSets = [] # List #def findRegressionFiles(inputFolder): for root, dirs, files in os.walk(inputFolder): for file in files: @@ -154,16 +195,7 @@ def parse_args(): return args -#def isSimulated(mstate): - -def parseNode(node, level = 0): - for child in node.children: - print (str(level) + " -> " + child.name.value) - mstate = child.getMechanicalState() - if (mstate): - print (" -> " + mstate.name.value) - parseNode(child, level+1) if __name__ == '__main__': @@ -177,10 +209,15 @@ def parseNode(node, level = 0): for i in range(0, 4): firstSet = prog.sceneSets[1] - print(firstSet.scenes[i].fileScenePath) - rootNode = Sofa.Simulation.load(firstSet.scenes[i].fileScenePath) - print("######## scene: " + str(firstSet.scenes[i].fileScenePath)) - parseNode(rootNode, 0) + sceneData = firstSet.scenes[i] + print(sceneData.fileScenePath) + rootNode = Sofa.Simulation.load(sceneData.fileScenePath) + print("######## scene: " + str(sceneData.fileScenePath)) + sceneData.parseNode(rootNode, 0) + sceneData.printInfo() + sceneData.printMecaObjs() + + #node = mstate.getContext() # if (!createReference) # { From 624e9ec46ed6a6beea0d99af2bcbb93d5b68e1b1 Mon Sep 17 00:00:00 2001 From: epernod Date: Fri, 14 Jun 2024 18:20:46 +0200 Subject: [PATCH 05/28] Backup work on saving data --- new_regression.py | 255 ++++++++++++++++++++++++++-------------------- 1 file changed, 145 insertions(+), 110 deletions(-) diff --git a/new_regression.py b/new_regression.py index f18e43d..cc3ae56 100644 --- a/new_regression.py +++ b/new_regression.py @@ -2,7 +2,10 @@ import argparse import sys import Sofa - +import numpy as np +from tqdm import tqdm +from json import JSONEncoder +import json debugInfo = True @@ -19,6 +22,38 @@ def isSimulated(node): return False +class NumpyArrayEncoder(JSONEncoder): + def default(self, obj): + if isinstance(obj, np.ndarray): + return obj.tolist() + return JSONEncoder.default(self, obj) + +def exportJson(): + + numpyArrayOne = np.array([[11 ,22, 33], [44, 55, 66], [77, 88, 99]]) + numpyArrayTwo = np.array([[51, 61, 91], [121 ,118, 127]]) + + # Serialization + numpyData = {"arrayOne": numpyArrayOne, "arrayTwo": numpyArrayTwo} + print("serialize NumPy array into JSON and write into a file") + with open("numpyData.json", "w") as write_file: + json.dump(numpyData, write_file, cls=NumpyArrayEncoder) + print("Done writing serialized NumPy array into file") + + # Deserialization + print("Started Reading JSON file") + with open("numpyData.json", "r") as read_file: + print("Converting JSON encoded data into Numpy array") + decodedArray = json.load(read_file) + + finalNumpyArrayOne = np.asarray(decodedArray["arrayOne"]) + print("NumPy Array One") + print(finalNumpyArrayOne) + finalNumpyArrayTwo = np.asarray(decodedArray["arrayTwo"]) + print("NumPy Array Two") + print(finalNumpyArrayTwo) + + class RegressionSceneData: def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1000, epsilon = 0.0001, mecaInMapping = True, dumpOnlyLastStep = False): @@ -43,20 +78,24 @@ def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1 self.mecaInMapping = mecaInMapping self.dumpOnlyLastStep = dumpOnlyLastStep self.mecaObjs = [] + self.fileNames = [] + self.mins = [] + self.maxs = [] def printInfo(self): print("Test scene: " + self.fileScenePath + " vs " + self.fileRefPath + " using: " + self.steps + " " + self.epsilon) + def printMecaObjs(self): print ("# Nbr Meca: " + str(len(self.mecaObjs))) counter = 0 for mecaObj in self.mecaObjs: filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" - counter = counter+1 print ("# toRead: " + filename) + def parseNode(self, node, level = 0): for child in node.children: mstate = child.getMechanicalState() @@ -66,12 +105,76 @@ def parseNode(self, node, level = 0): self.parseNode(child, level+1) - # def addCompareState(self): - # for mecaObj in self.mecaObjs: - # mecaObj.getContext().addObject('CompareState') - # print ("# toRead: " + mecaObj.name.value) + + def addCompareState(self): + counter = 0 + for mecaObj in self.mecaObjs: + _filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" + + mecaObj.getContext().addObject('CompareState', filename=_filename) + counter = counter+1 + + + def addWriteState(self): + counter = 0 + for mecaObj in self.mecaObjs: + _filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" + + mecaObj.getContext().addObject('WriteState', filename=_filename) + counter = counter+1 + def loadScene(self): + self.rootNode = Sofa.Simulation.load(self.fileScenePath) + self.rootNode.addObject('RequiredPlugin', pluginName="SofaValidation") + Sofa.Simulation.init(self.rootNode) + + # prepare ref files per mecaObjs: + self.parseNode(self.rootNode, 0) + counter = 0 + for mecaObj in self.mecaObjs: + _filename = self.fileRefPath + ".reference_mstate_" + str(counter) + "_" + mecaObj.name.value + ".json" + self.fileNames.append(_filename) + counter = counter+1 + + + def dumpDofs(self): + pbarSimu = tqdm(total=10) #self.steps + pbarSimu.set_description("Simulate: " + self.fileScenePath) + + #numpyData = {"T": 0, "X": self.mecaObjs[0].position.value} + numpyData = [] + numpyData.append({"T": 0, "X": self.mecaObjs[0].position.value}) + for j in range(0, 10): # self.steps + Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) + numpyData.append({"T": str(j), "X": self.mecaObjs[0].position.value}) + pbarSimu.update(1) + pbarSimu.close() + + + + with open("numpyData.json", "w") as write_file: + json.dump(numpyData, write_file, cls=NumpyArrayEncoder) + print("Done writing serialized NumPy array into file") + + print ("dt: " + str(numpyData)) + # export Data + # counter = 0 + # for mecaObj in self.mecaObjs: + # dofs = mecaObj.position.value + + # self.mins.append(np.min(dofs, axis=0)) + # self.maxs.append(np.max(dofs, axis=0)) + + # #print ("dof: " + str(len(dofs)) + " -> [" + str(self.mins[counter]) + str(self.maxs[counter]) + "]") + # # Serialization + # #numpyData = {"dofs": dofs} + # print ("writting: " + self.fileNames[counter]) + # # with open(self.fileNames[counter], "w") as write_file: + # # json.dump(numpyData, write_file, cls=NumpyArrayEncoder) + # # print("Done writing: " + self.fileNames[counter]) + # counter = counter + 1 + class RegressionSceneList: def __init__(self, filePath): @@ -96,7 +199,6 @@ def processFile(self): continue if (count == 0): - print("Line ref: " + values[0]) self.refDirPath = os.path.join(self.fileDir, values[0]) self.refDirPath = os.path.abspath(self.refDirPath) count = count + 1 @@ -119,23 +221,26 @@ def processFile(self): self.scenes.append(sceneData) print("## nbrScenes: " + str(len(self.scenes))) - # target = "SetTopologyAlgorithms" - - # new_file = open(filePath, "w") - - # for idx, line in enumerate(data): - # if re.search(target, line): - # continue; - - # new_file.write(line) - - # new_file.close() + def writeReferences(self, idScene): + self.scenes[idScene].loadScene() + self.scenes[idScene].printMecaObjs() + self.scenes[idScene].dumpDofs() + + def writeAllReferences(self): + nbrScenes = len(self.scenes) + pbarScenes = tqdm(total=nbrScenes) + pbarScenes.set_description("Write all scenes from: " + self.filePath) + for i in range(0, nbrScenes): + self.writeReferences(i) + pbarScenes.update(1) + pbarScenes.close() + class RegressionProgram: def __init__(self, inputFolder): self.sceneSets = [] # List -#def findRegressionFiles(inputFolder): + for root, dirs, files in os.walk(inputFolder): for file in files: if file.endswith(".regression-tests"): @@ -145,25 +250,21 @@ def __init__(self, inputFolder): sceneList.processFile() self.sceneSets.append(sceneList) - # if (debugInfo): - # print("Regression file found: " + filePath) - - # access header and store all includes - # with open(filePath, 'r') as thefile: - # data = thefile.readlines() - # thefile.close() - - # target = "SetTopologyAlgorithms" - - # new_file = open(filePath, "w") - - # for idx, line in enumerate(data): - # if re.search(target, line): - # continue; - - # new_file.write(line) - - # new_file.close() + + def writeSetReferences(self, idSet = 0): + sceneData = self.sceneSets[idSet] + #sceneData.writeAllReferences() + sceneData.writeReferences(0) + sceneData.writeReferences(1) + + def writeAllSetsReferences(self): + nbrSets = len(self.sceneSets) + pbarSets = tqdm(total=nbrSets) + pbarSets.set_description("Write All sets") + for i in range(0, nbrSets): + self.writeSetReferences(i) + pbarSets.update(1) + pbarSets.close() @@ -204,77 +305,11 @@ def parse_args(): # 2- Process file prog = RegressionProgram(args.input) - - print ("### Number of sets: " + str(len(prog.sceneSets))) - for i in range(0, 4): - firstSet = prog.sceneSets[1] - sceneData = firstSet.scenes[i] - print(sceneData.fileScenePath) - rootNode = Sofa.Simulation.load(sceneData.fileScenePath) - print("######## scene: " + str(sceneData.fileScenePath)) - sceneData.parseNode(rootNode, 0) - sceneData.printInfo() - sceneData.printMecaObjs() - - #node = mstate.getContext() - - # if (!createReference) - # { - # // Add CompareState components: as it derives from the ReadState, we use the ReadStateActivator to enable them. - # sofa::component::playback::CompareStateCreator compareVisitor(sofa::core::ExecParams::defaultInstance()); - - # compareVisitor.setCreateInMapping(data.m_mecaInMapping); - # compareVisitor.setSceneName(data.m_fileRefPath); - # compareVisitor.execute(root.get()); - - # sofa::component::playback::ReadStateActivator v_read(sofa::core::ExecParams::defaultInstance() /* PARAMS FIRST */, true); - # v_read.execute(root.get()); - # } - # else // create reference - # { - # msg_warning("StateRegression_test::runTestImpl") << "Non existing reference created: " << data.m_fileRefPath; - - # // just to create an empty file to know it is already init - # std::ofstream filestream(data.m_fileRefPath.c_str()); - # filestream.close(); - - # sofa::component::playback::WriteStateCreator writeVisitor(sofa::core::ExecParams::defaultInstance()); - - # if (data.m_dumpOnlyLastStep) - # { - # std::vector times; - # times.push_back(0.0); - # times.push_back(root->getDt() * (data.m_steps - 1)); - # writeVisitor.setExportTimes(times); - # } - # writeVisitor.setCreateInMapping(data.m_mecaInMapping); - # writeVisitor.setSceneName(data.m_fileRefPath); - # writeVisitor.execute(root.get()); - - # sofa::component::playback::WriteStateActivator v_write(sofa::core::ExecParams::defaultInstance() /* PARAMS FIRST */, true); - # v_write.execute(root.get()); - # } - - # for (unsigned int i = 0; igetDt()); - # } - - # if (!createReference) - # { - # // Read the final error: the summation of all the error made at each time step - # sofa::component::playback::CompareStateResult result(sofa::core::ExecParams::defaultInstance()); - # result.execute(root.get()); - - # double errorByDof = result.getErrorByDof() / double(result.getNumCompareState()); - # if (errorByDof > data.m_epsilon) - # { - # msg_error("StateRegression_test::runTestImpl") - # << data.m_fileScenePath << ":" << msgendl - # << " TOTALERROR: " << result.getTotalError() << msgendl - # << " ERRORBYDOF: " << errorByDof; - # } - # } - + #exportJson() + + print ("### Number of sets: " + str(len(prog.sceneSets))) + #prog.writeAllSetsReferences() + prog.writeSetReferences(1) + print ("### Number of sets: Done ") \ No newline at end of file From cd0908240a0c0ca8caf82a64996bf23b596270b2 Mon Sep 17 00:00:00 2001 From: epernod Date: Wed, 19 Jun 2024 01:05:07 +0200 Subject: [PATCH 06/28] Update code to dump directly a map and add code to reload files. Not working yet. --- new_regression.py | 119 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 21 deletions(-) diff --git a/new_regression.py b/new_regression.py index cc3ae56..6d644f0 100644 --- a/new_regression.py +++ b/new_regression.py @@ -6,6 +6,7 @@ from tqdm import tqdm from json import JSONEncoder import json +import zlib debugInfo = True @@ -40,6 +41,7 @@ def exportJson(): json.dump(numpyData, write_file, cls=NumpyArrayEncoder) print("Done writing serialized NumPy array into file") +def readJson(): # Deserialization print("Started Reading JSON file") with open("numpyData.json", "r") as read_file: @@ -138,26 +140,68 @@ def loadScene(self): counter = counter+1 - def dumpDofs(self): + def writeReferences(self): pbarSimu = tqdm(total=10) #self.steps pbarSimu.set_description("Simulate: " + self.fileScenePath) - #numpyData = {"T": 0, "X": self.mecaObjs[0].position.value} - numpyData = [] - numpyData.append({"T": 0, "X": self.mecaObjs[0].position.value}) - for j in range(0, 10): # self.steps - Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) - numpyData.append({"T": str(j), "X": self.mecaObjs[0].position.value}) - pbarSimu.update(1) - pbarSimu.close() + counter = 0 + for mecaObj in self.mecaObjs: + #numpyData = {"T": 0, "X": self.mecaObjs[0].position.value} + numpyData = {0: mecaObj.position.value} + #numpyData.append({"T": 0, "X": self.mecaObjs[0].position.value}) + for j in range(0, 10): # self.steps + Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) + #numpyData.append({"T": str(self.rootNode.dt.value*(j+1)), "X": self.mecaObjs[0].position.value}) + numpyData[self.rootNode.dt.value*(j+1)] = mecaObj.position.value + pbarSimu.update(1) + pbarSimu.close() + + + + with open(self.fileNames[counter], "w") as write_file: + json.dump(numpyData, write_file, cls=NumpyArrayEncoder) + json.dump(numpyData, write_file, cls=NumpyArrayEncoder) + print("Done writing: " + self.fileNames[counter]) + counter = counter+1 + + + def compareReferences(self): + pbarSimu = tqdm(total=10) #self.steps + pbarSimu.set_description("Simulate: " + self.fileScenePath) + + counter = 0 + for mecaObj in self.mecaObjs: + print("read: " + self.fileNames[counter]) + with open(self.fileNames[counter], "r") as read_file: + decodedArray = json.load(read_file) + #numpyArray = decodedArray[0] + + + #finalNumpyArrayOne = np.asarray(decodedArray["arrayOne"]) + + + # counter = 0 + # for mecaObj in self.mecaObjs: + # #numpyData = {"T": 0, "X": self.mecaObjs[0].position.value} + # numpyData = [] + # numpyData.append({"T": 0, "X": self.mecaObjs[0].position.value}) + # for j in range(0, 10): # self.steps + # Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) + # numpyData.append({"T": str(self.rootNode.dt.value*(j+1)), "X": self.mecaObjs[0].position.value}) + # pbarSimu.update(1) + # pbarSimu.close() + + + # with open(self.fileNames[counter], "w") as write_file: + # json.dump(numpyData, write_file, cls=NumpyArrayEncoder) + # json.dump(numpyData, write_file, cls=NumpyArrayEncoder) + # print("Done writing: " + self.fileNames[counter]) - with open("numpyData.json", "w") as write_file: - json.dump(numpyData, write_file, cls=NumpyArrayEncoder) - print("Done writing serialized NumPy array into file") + # counter = counter+1 - print ("dt: " + str(numpyData)) + #print ("dt: " + str(numpyData)) # export Data # counter = 0 # for mecaObj in self.mecaObjs: @@ -224,8 +268,8 @@ def processFile(self): def writeReferences(self, idScene): self.scenes[idScene].loadScene() - self.scenes[idScene].printMecaObjs() - self.scenes[idScene].dumpDofs() + #self.scenes[idScene].printMecaObjs() + self.scenes[idScene].writeReferences() def writeAllReferences(self): nbrScenes = len(self.scenes) @@ -235,7 +279,21 @@ def writeAllReferences(self): self.writeReferences(i) pbarScenes.update(1) pbarScenes.close() + + + def compareReferences(self, idScene): + self.scenes[idScene].loadScene() + self.scenes[idScene].compareReferences() + def compareAllReferences(self): + nbrScenes = len(self.scenes) + pbarScenes = tqdm(total=nbrScenes) + pbarScenes.set_description("Compare all scenes from: " + self.filePath) + for i in range(0, nbrScenes): + self.compareReferences(i) + pbarScenes.update(1) + pbarScenes.close() + class RegressionProgram: def __init__(self, inputFolder): @@ -267,6 +325,22 @@ def writeAllSetsReferences(self): pbarSets.close() + def compareSetsReferences(self, idSet = 0): + sceneData = self.sceneSets[idSet] + #sceneData.writeAllReferences() + sceneData.compareReferences(0) + sceneData.compareReferences(1) + + def compareAllSetsReferences(self): + nbrSets = len(self.sceneSets) + pbarSets = tqdm(total=nbrSets) + pbarSets.set_description("Write All sets") + for i in range(0, nbrSets): + self.compareReferences(i) + pbarSets.update(1) + pbarSets.close() + + def parse_args(): """ @@ -285,10 +359,10 @@ def parse_args(): type=str) parser.add_argument( - "--classify", - dest="classify", + "--writeRef", + dest="writeMode", default=False, - help='Sort files into folders per class' + help='If true, will generate new reference files' ) args = parser.parse_args() @@ -306,10 +380,13 @@ def parse_args(): # 2- Process file prog = RegressionProgram(args.input) - #exportJson() print ("### Number of sets: " + str(len(prog.sceneSets))) - #prog.writeAllSetsReferences() - prog.writeSetReferences(1) + if (args.writeMode): + #prog.writeAllSetsReferences() + prog.writeSetReferences(1) + else: + readJson() + prog.compareSetsReferences(1) print ("### Number of sets: Done ") \ No newline at end of file From ea5e979c3382dc4bbff5bc1ea84d97160405efc6 Mon Sep 17 00:00:00 2001 From: epernod Date: Thu, 15 Aug 2024 23:18:41 +0200 Subject: [PATCH 07/28] Fix python scene support in new_regression script --- new_regression.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/new_regression.py b/new_regression.py index 6d644f0..8826f86 100644 --- a/new_regression.py +++ b/new_regression.py @@ -2,6 +2,7 @@ import argparse import sys import Sofa +import SofaRuntime import numpy as np from tqdm import tqdm from json import JSONEncoder @@ -376,17 +377,18 @@ def parse_args(): if __name__ == '__main__': # 1- Parse arguments to get folder path args = parse_args() - # 2- Process file - prog = RegressionProgram(args.input) - + regProg = RegressionProgram(args.input) + SofaRuntime.importPlugin("SofaPython3") - print ("### Number of sets: " + str(len(prog.sceneSets))) + print ("### Number of sets: " + str(len(regProg.sceneSets))) if (args.writeMode): #prog.writeAllSetsReferences() - prog.writeSetReferences(1) + #regProg.writeSetsReferences(0) else: readJson() - prog.compareSetsReferences(1) - print ("### Number of sets: Done ") + regProg.compareSetsReferences(0) + print ("### Number of sets Done: " + str(len(regProg.sceneSets))) + sys.exit() + \ No newline at end of file From 476fffcab3b472e1ddb2f77ae085e716f08a8d46 Mon Sep 17 00:00:00 2001 From: epernod Date: Thu, 15 Aug 2024 23:18:56 +0200 Subject: [PATCH 08/28] Fix export of numpy data --- new_regression.py | 85 ++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/new_regression.py b/new_regression.py index 8826f86..a06d698 100644 --- a/new_regression.py +++ b/new_regression.py @@ -96,7 +96,7 @@ def printMecaObjs(self): for mecaObj in self.mecaObjs: filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" counter = counter+1 - print ("# toRead: " + filename) + print ("# File attached: " + filename) def parseNode(self, node, level = 0): @@ -129,9 +129,9 @@ def addWriteState(self): def loadScene(self): self.rootNode = Sofa.Simulation.load(self.fileScenePath) - self.rootNode.addObject('RequiredPlugin', pluginName="SofaValidation") + #self.rootNode.addObject('RequiredPlugin', pluginName="SofaValidation") Sofa.Simulation.init(self.rootNode) - + # prepare ref files per mecaObjs: self.parseNode(self.rootNode, 0) counter = 0 @@ -139,33 +139,44 @@ def loadScene(self): _filename = self.fileRefPath + ".reference_mstate_" + str(counter) + "_" + mecaObj.name.value + ".json" self.fileNames.append(_filename) counter = counter+1 + def writeReferences(self): pbarSimu = tqdm(total=10) #self.steps pbarSimu.set_description("Simulate: " + self.fileScenePath) - - counter = 0 - for mecaObj in self.mecaObjs: - #numpyData = {"T": 0, "X": self.mecaObjs[0].position.value} - numpyData = {0: mecaObj.position.value} - #numpyData.append({"T": 0, "X": self.mecaObjs[0].position.value}) - for j in range(0, 10): # self.steps - Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) - #numpyData.append({"T": str(self.rootNode.dt.value*(j+1)), "X": self.mecaObjs[0].position.value}) - numpyData[self.rootNode.dt.value*(j+1)] = mecaObj.position.value - pbarSimu.update(1) - pbarSimu.close() - + + nbrMeca = len(self.mecaObjs) + numpyData = [] # List + for mecaId in range(0, nbrMeca): + mecaDofs = {} + numpyData.append(mecaDofs) + + counterStep = 0 + nbrStep = 1000 + for step in range(0, nbrStep): + Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) + if (counterStep == 499): + for mecaId in range(0, nbrMeca): + numpyData[mecaId][self.rootNode.dt.value*(step)] = np.copy(self.mecaObjs[mecaId].position.value) + #print(self.mecaObjs[mecaId].position.value[820]) + counterStep = 0 + + counterStep = counterStep + 1 + pbarSimu.update(1) + pbarSimu.close() + + for mecaId in range(0, nbrMeca): + #for key in numpyData[mecaId]: + # print("key: %s , value: %s" % (key, numpyData[mecaId][key][820])) + with open(self.fileNames[mecaId], "w") as write_file: + json.dump(numpyData[mecaId], write_file, cls=NumpyArrayEncoder) + + print("Done writing: " + self.fileNames[mecaId]) - with open(self.fileNames[counter], "w") as write_file: - json.dump(numpyData, write_file, cls=NumpyArrayEncoder) - json.dump(numpyData, write_file, cls=NumpyArrayEncoder) - print("Done writing: " + self.fileNames[counter]) - - counter = counter+1 - + Sofa.Simulation.unload(self.rootNode) + def compareReferences(self): pbarSimu = tqdm(total=10) #self.steps @@ -269,17 +280,17 @@ def processFile(self): def writeReferences(self, idScene): self.scenes[idScene].loadScene() - #self.scenes[idScene].printMecaObjs() + self.scenes[idScene].printMecaObjs() self.scenes[idScene].writeReferences() def writeAllReferences(self): nbrScenes = len(self.scenes) - pbarScenes = tqdm(total=nbrScenes) - pbarScenes.set_description("Write all scenes from: " + self.filePath) + #pbarScenes = tqdm(total=nbrScenes) + #pbarScenes.set_description("Write all scenes from: " + self.filePath) for i in range(0, nbrScenes): self.writeReferences(i) - pbarScenes.update(1) - pbarScenes.close() + #pbarScenes.update(1) + #pbarScenes.close() def compareReferences(self, idScene): @@ -296,6 +307,7 @@ def compareAllReferences(self): pbarScenes.close() + class RegressionProgram: def __init__(self, inputFolder): self.sceneSets = [] # List @@ -310,11 +322,9 @@ def __init__(self, inputFolder): sceneList.processFile() self.sceneSets.append(sceneList) - def writeSetReferences(self, idSet = 0): - sceneData = self.sceneSets[idSet] - #sceneData.writeAllReferences() - sceneData.writeReferences(0) - sceneData.writeReferences(1) + def writeSetsReferences(self, idSet = 0): + sceneList = self.sceneSets[idSet] + sceneList.writeAllReferences() def writeAllSetsReferences(self): nbrSets = len(self.sceneSets) @@ -327,10 +337,10 @@ def writeAllSetsReferences(self): def compareSetsReferences(self, idSet = 0): - sceneData = self.sceneSets[idSet] - #sceneData.writeAllReferences() - sceneData.compareReferences(0) - sceneData.compareReferences(1) + sceneList = self.sceneSets[idSet] + #sceneList.writeAllReferences() + sceneList.compareReferences(0) + sceneList.compareReferences(1) def compareAllSetsReferences(self): nbrSets = len(self.sceneSets) @@ -385,6 +395,7 @@ def parse_args(): if (args.writeMode): #prog.writeAllSetsReferences() #regProg.writeSetsReferences(0) + exportJson() else: readJson() regProg.compareSetsReferences(0) From 9ce9190ace0a4f944da3ff3a4af0ef70c2b7091d Mon Sep 17 00:00:00 2001 From: epernod Date: Fri, 16 Aug 2024 00:11:20 +0200 Subject: [PATCH 09/28] Add file compression --- new_regression.py | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/new_regression.py b/new_regression.py index a06d698..4b97ef6 100644 --- a/new_regression.py +++ b/new_regression.py @@ -7,7 +7,7 @@ from tqdm import tqdm from json import JSONEncoder import json -import zlib +import gzip debugInfo = True @@ -38,16 +38,27 @@ def exportJson(): # Serialization numpyData = {"arrayOne": numpyArrayOne, "arrayTwo": numpyArrayTwo} print("serialize NumPy array into JSON and write into a file") - with open("numpyData.json", "w") as write_file: - json.dump(numpyData, write_file, cls=NumpyArrayEncoder) + with gzip.open("numpyData.json.gz", 'w') as zipfile: + for key in numpyData: + print(numpyData[key]) + + #write_file.write(json.dumps(numpyData, cls=NumpyArrayEncoder, indent=4)) + #res = json.dumps(numpyData, cls=NumpyArrayEncoder, indent=4) + #print(res) + #json.dump(numpyData, zipfile, cls=NumpyArrayEncoder) + zipfile.write(json.dumps(numpyData, cls=NumpyArrayEncoder).encode('utf-8')) + print("Done writing serialized NumPy array into file") def readJson(): # Deserialization print("Started Reading JSON file") - with open("numpyData.json", "r") as read_file: + with gzip.open("numpyData.json.gz", 'r') as zipfile: + + #with open("numpyData.json", "r") as read_file: print("Converting JSON encoded data into Numpy array") - decodedArray = json.load(read_file) + decodedArray = json.loads(zipfile.read().decode('utf-8')) + #decodedArray = json.load(zipfile) finalNumpyArrayOne = np.asarray(decodedArray["arrayOne"]) print("NumPy Array One") @@ -136,7 +147,7 @@ def loadScene(self): self.parseNode(self.rootNode, 0) counter = 0 for mecaObj in self.mecaObjs: - _filename = self.fileRefPath + ".reference_mstate_" + str(counter) + "_" + mecaObj.name.value + ".json" + _filename = self.fileRefPath + ".reference_mstate_" + str(counter) + "_" + mecaObj.name.value + ".json.gz" self.fileNames.append(_filename) counter = counter+1 @@ -170,8 +181,9 @@ def writeReferences(self): for mecaId in range(0, nbrMeca): #for key in numpyData[mecaId]: # print("key: %s , value: %s" % (key, numpyData[mecaId][key][820])) - with open(self.fileNames[mecaId], "w") as write_file: - json.dump(numpyData[mecaId], write_file, cls=NumpyArrayEncoder) + with gzip.open(self.fileNames[mecaId], "w") as write_file: + #json.dump(numpyData[mecaId], write_file, cls=NumpyArrayEncoder) + write_file.write(json.dumps(numpyData[mecaId], cls=NumpyArrayEncoder).encode('utf-8')) print("Done writing: " + self.fileNames[mecaId]) @@ -394,11 +406,11 @@ def parse_args(): print ("### Number of sets: " + str(len(regProg.sceneSets))) if (args.writeMode): #prog.writeAllSetsReferences() - #regProg.writeSetsReferences(0) - exportJson() + regProg.writeSetsReferences(0) + #exportJson() else: readJson() - regProg.compareSetsReferences(0) + #regProg.compareSetsReferences(0) print ("### Number of sets Done: " + str(len(regProg.sceneSets))) sys.exit() From 97fd6ccdccb82f0bd390b72bffbc2a6aa02662a1 Mon Sep 17 00:00:00 2001 From: epernod Date: Fri, 16 Aug 2024 01:14:46 +0200 Subject: [PATCH 10/28] backup work on comparison --- new_regression.py | 74 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/new_regression.py b/new_regression.py index 4b97ef6..bc3d7f7 100644 --- a/new_regression.py +++ b/new_regression.py @@ -154,7 +154,7 @@ def loadScene(self): def writeReferences(self): - pbarSimu = tqdm(total=10) #self.steps + pbarSimu = tqdm(total=1000) #self.steps pbarSimu.set_description("Simulate: " + self.fileScenePath) nbrMeca = len(self.mecaObjs) @@ -191,15 +191,51 @@ def writeReferences(self): def compareReferences(self): - pbarSimu = tqdm(total=10) #self.steps - pbarSimu.set_description("Simulate: " + self.fileScenePath) + #pbarSimu = tqdm(total=1000) #self.steps + #pbarSimu.set_description("compareReferences: " + self.fileScenePath) - counter = 0 - for mecaObj in self.mecaObjs: - print("read: " + self.fileNames[counter]) - with open(self.fileNames[counter], "r") as read_file: - decodedArray = json.load(read_file) - #numpyArray = decodedArray[0] + nbrMeca = len(self.mecaObjs) + numpyData = [] # List + keyframes = [] + for mecaId in range(0, nbrMeca): + with gzip.open(self.fileNames[mecaId], 'r') as zipfile: + print("Converting JSON encoded data into Numpy array") + + decodedArray = json.loads(zipfile.read().decode('utf-8')) + numpyData.append(decodedArray) + + if (mecaId is 0): + for key in decodedArray: + keyframes.append(float(key)) + + print("keyframes: " + str(keyframes)) + + frameStep = 0 + nbrFrames = len(keyframes) + nbrStep = 1000 + for step in range(0, nbrStep): + Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) + simuTime = self.rootNode.dt.value*(step) + #print ("time: " + str(simuTime)) + if (simuTime == keyframes[frameStep]): + print("### Found same time: " + str(keyframes[frameStep])) + + for mecaId in range(0, nbrMeca): + #numpyData[mecaId][self.rootNode.dt.value*(step)] = np.copy(self.mecaObjs[mecaId].position.value) + print(self.mecaObjs[mecaId].position.value[820]) + mecaDofs = np.copy(self.mecaObjs[mecaId].position.value) + dataRef = np.asarray(numpyData[mecaId][str(keyframes[frameStep])]) - mecaDofs + print(dataRef[820]) + dist = np.linalg.norm(dataRef) + print("dist: " + str(dist)) + + frameStep = frameStep + 1 + if (frameStep == nbrFrames): + print ("exit comparison") + return + + #pbarSimu.update(1) + #pbarSimu.close() #finalNumpyArrayOne = np.asarray(decodedArray["arrayOne"]) @@ -292,7 +328,7 @@ def processFile(self): def writeReferences(self, idScene): self.scenes[idScene].loadScene() - self.scenes[idScene].printMecaObjs() + #self.scenes[idScene].printMecaObjs() self.scenes[idScene].writeReferences() def writeAllReferences(self): @@ -311,12 +347,12 @@ def compareReferences(self, idScene): def compareAllReferences(self): nbrScenes = len(self.scenes) - pbarScenes = tqdm(total=nbrScenes) - pbarScenes.set_description("Compare all scenes from: " + self.filePath) + #pbarScenes = tqdm(total=nbrScenes) + #pbarScenes.set_description("Compare all scenes from: " + self.filePath) for i in range(0, nbrScenes): self.compareReferences(i) - pbarScenes.update(1) - pbarScenes.close() + # pbarScenes.update(1) + #pbarScenes.close() @@ -350,10 +386,8 @@ def writeAllSetsReferences(self): def compareSetsReferences(self, idSet = 0): sceneList = self.sceneSets[idSet] - #sceneList.writeAllReferences() - sceneList.compareReferences(0) - sceneList.compareReferences(1) - + sceneList.compareAllReferences() + def compareAllSetsReferences(self): nbrSets = len(self.sceneSets) pbarSets = tqdm(total=nbrSets) @@ -409,8 +443,8 @@ def parse_args(): regProg.writeSetsReferences(0) #exportJson() else: - readJson() - #regProg.compareSetsReferences(0) + #readJson() + regProg.compareSetsReferences(0) print ("### Number of sets Done: " + str(len(regProg.sceneSets))) sys.exit() From cd7f598b224c90909dca0489206bd0d00e452092 Mon Sep 17 00:00:00 2001 From: epernod Date: Mon, 19 Aug 2024 14:54:17 +0200 Subject: [PATCH 11/28] clean code --- new_regression.py | 115 +++++++++++++--------------------------------- 1 file changed, 32 insertions(+), 83 deletions(-) diff --git a/new_regression.py b/new_regression.py index bc3d7f7..606d6ac 100644 --- a/new_regression.py +++ b/new_regression.py @@ -68,6 +68,7 @@ def readJson(): print(finalNumpyArrayTwo) + class RegressionSceneData: def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1000, epsilon = 0.0001, mecaInMapping = True, dumpOnlyLastStep = False): @@ -87,8 +88,8 @@ def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1 """ self.fileScenePath = fileScenePath self.fileRefPath = fileRefPath - self.steps = steps - self.epsilon = epsilon + self.steps = int(steps) + self.epsilon = float(epsilon) self.mecaInMapping = mecaInMapping self.dumpOnlyLastStep = dumpOnlyLastStep self.mecaObjs = [] @@ -140,7 +141,6 @@ def addWriteState(self): def loadScene(self): self.rootNode = Sofa.Simulation.load(self.fileScenePath) - #self.rootNode.addObject('RequiredPlugin', pluginName="SofaValidation") Sofa.Simulation.init(self.rootNode) # prepare ref files per mecaObjs: @@ -154,8 +154,9 @@ def loadScene(self): def writeReferences(self): - pbarSimu = tqdm(total=1000) #self.steps - pbarSimu.set_description("Simulate: " + self.fileScenePath) + + #pbarSimu = tqdm(total=self.steps) + #pbarSimu.set_description("Simulate: " + self.fileScenePath) nbrMeca = len(self.mecaObjs) numpyData = [] # List @@ -164,43 +165,36 @@ def writeReferences(self): numpyData.append(mecaDofs) counterStep = 0 - nbrStep = 1000 - for step in range(0, nbrStep): + for step in range(0, self.steps): Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) if (counterStep == 499): for mecaId in range(0, nbrMeca): numpyData[mecaId][self.rootNode.dt.value*(step)] = np.copy(self.mecaObjs[mecaId].position.value) - #print(self.mecaObjs[mecaId].position.value[820]) counterStep = 0 counterStep = counterStep + 1 - pbarSimu.update(1) - pbarSimu.close() + #pbarSimu.update(1) + #pbarSimu.close() for mecaId in range(0, nbrMeca): #for key in numpyData[mecaId]: # print("key: %s , value: %s" % (key, numpyData[mecaId][key][820])) with gzip.open(self.fileNames[mecaId], "w") as write_file: - #json.dump(numpyData[mecaId], write_file, cls=NumpyArrayEncoder) write_file.write(json.dumps(numpyData[mecaId], cls=NumpyArrayEncoder).encode('utf-8')) - - print("Done writing: " + self.fileNames[mecaId]) Sofa.Simulation.unload(self.rootNode) def compareReferences(self): - #pbarSimu = tqdm(total=1000) #self.steps - #pbarSimu.set_description("compareReferences: " + self.fileScenePath) + pbarSimu = tqdm(total=float(self.steps)) + pbarSimu.set_description("compareReferences: " + self.fileScenePath) nbrMeca = len(self.mecaObjs) numpyData = [] # List keyframes = [] for mecaId in range(0, nbrMeca): with gzip.open(self.fileNames[mecaId], 'r') as zipfile: - print("Converting JSON encoded data into Numpy array") - decodedArray = json.loads(zipfile.read().decode('utf-8')) numpyData.append(decodedArray) @@ -208,12 +202,9 @@ def compareReferences(self): for key in decodedArray: keyframes.append(float(key)) - print("keyframes: " + str(keyframes)) - frameStep = 0 nbrFrames = len(keyframes) - nbrStep = 1000 - for step in range(0, nbrStep): + for step in range(0, self.steps): Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) simuTime = self.rootNode.dt.value*(step) #print ("time: " + str(simuTime)) @@ -234,50 +225,8 @@ def compareReferences(self): print ("exit comparison") return - #pbarSimu.update(1) - #pbarSimu.close() - - - #finalNumpyArrayOne = np.asarray(decodedArray["arrayOne"]) - - - # counter = 0 - # for mecaObj in self.mecaObjs: - # #numpyData = {"T": 0, "X": self.mecaObjs[0].position.value} - # numpyData = [] - # numpyData.append({"T": 0, "X": self.mecaObjs[0].position.value}) - # for j in range(0, 10): # self.steps - # Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) - # numpyData.append({"T": str(self.rootNode.dt.value*(j+1)), "X": self.mecaObjs[0].position.value}) - # pbarSimu.update(1) - # pbarSimu.close() - - - - # with open(self.fileNames[counter], "w") as write_file: - # json.dump(numpyData, write_file, cls=NumpyArrayEncoder) - # json.dump(numpyData, write_file, cls=NumpyArrayEncoder) - # print("Done writing: " + self.fileNames[counter]) - - # counter = counter+1 - - #print ("dt: " + str(numpyData)) - # export Data - # counter = 0 - # for mecaObj in self.mecaObjs: - # dofs = mecaObj.position.value - - # self.mins.append(np.min(dofs, axis=0)) - # self.maxs.append(np.max(dofs, axis=0)) - - # #print ("dof: " + str(len(dofs)) + " -> [" + str(self.mins[counter]) + str(self.maxs[counter]) + "]") - # # Serialization - # #numpyData = {"dofs": dofs} - # print ("writting: " + self.fileNames[counter]) - # # with open(self.fileNames[counter], "w") as write_file: - # # json.dump(numpyData, write_file, cls=NumpyArrayEncoder) - # # print("Done writing: " + self.fileNames[counter]) - # counter = counter + 1 + pbarSimu.update(1) + pbarSimu.close() class RegressionSceneList: @@ -326,9 +275,11 @@ def processFile(self): print("## nbrScenes: " + str(len(self.scenes))) - def writeReferences(self, idScene): + def writeReferences(self, idScene, printLog = False): self.scenes[idScene].loadScene() - #self.scenes[idScene].printMecaObjs() + if (printLog is True): + self.scenes[idScene].printMecaObjs() + self.scenes[idScene].writeReferences() def writeAllReferences(self): @@ -347,12 +298,12 @@ def compareReferences(self, idScene): def compareAllReferences(self): nbrScenes = len(self.scenes) - #pbarScenes = tqdm(total=nbrScenes) - #pbarScenes.set_description("Compare all scenes from: " + self.filePath) + pbarScenes = tqdm(total=nbrScenes) + pbarScenes.set_description("Compare all scenes from: " + self.filePath) for i in range(0, nbrScenes): self.compareReferences(i) - # pbarScenes.update(1) - #pbarScenes.close() + pbarScenes.update(1) + pbarScenes.close() @@ -376,12 +327,12 @@ def writeSetsReferences(self, idSet = 0): def writeAllSetsReferences(self): nbrSets = len(self.sceneSets) - pbarSets = tqdm(total=nbrSets) - pbarSets.set_description("Write All sets") + #pbarSets = tqdm(total=nbrSets) + #pbarSets.set_description("Write All sets") for i in range(0, nbrSets): - self.writeSetReferences(i) - pbarSets.update(1) - pbarSets.close() + self.writeSetsReferences(i) + #pbarSets.update(1) + #pbarSets.close() def compareSetsReferences(self, idSet = 0): @@ -391,9 +342,9 @@ def compareSetsReferences(self, idSet = 0): def compareAllSetsReferences(self): nbrSets = len(self.sceneSets) pbarSets = tqdm(total=nbrSets) - pbarSets.set_description("Write All sets") + pbarSets.set_description("Compare All sets") for i in range(0, nbrSets): - self.compareReferences(i) + self.compareSetsReferences(i) pbarSets.update(1) pbarSets.close() @@ -439,13 +390,11 @@ def parse_args(): print ("### Number of sets: " + str(len(regProg.sceneSets))) if (args.writeMode): - #prog.writeAllSetsReferences() - regProg.writeSetsReferences(0) - #exportJson() + regProg.writeAllSetsReferences() else: - #readJson() - regProg.compareSetsReferences(0) + regProg.compareAllSetsReferences(0) print ("### Number of sets Done: " + str(len(regProg.sceneSets))) + sys.exit() \ No newline at end of file From f36e015db8f3366cbb0cd5b59eee58443ef059f6 Mon Sep 17 00:00:00 2001 From: epernod Date: Mon, 19 Aug 2024 16:28:02 +0200 Subject: [PATCH 12/28] Fix period export --- new_regression.py | 49 ++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/new_regression.py b/new_regression.py index 606d6ac..bad7790 100644 --- a/new_regression.py +++ b/new_regression.py @@ -71,7 +71,7 @@ def readJson(): class RegressionSceneData: def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1000, - epsilon = 0.0001, mecaInMapping = True, dumpOnlyLastStep = False): + epsilon = 0.0001, mecaInMapping = True, dumpNumberStep = 1): """ /// Path to the file scene to test std::string m_fileScenePath; @@ -84,14 +84,14 @@ def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1 /// Option to test mechanicalObject in Node containing a Mapping (true will test them) bool m_mecaInMapping; /// Option to compare mechanicalObject dof position at each timestep - bool m_dumpOnlyLastStep; + bool m_dumpNumberStep; """ self.fileScenePath = fileScenePath self.fileRefPath = fileRefPath - self.steps = int(steps) + self.steps = int(steps) + 1 self.epsilon = float(epsilon) self.mecaInMapping = mecaInMapping - self.dumpOnlyLastStep = dumpOnlyLastStep + self.dumpNumberStep = int(dumpNumberStep) self.mecaObjs = [] self.fileNames = [] self.mins = [] @@ -154,9 +154,8 @@ def loadScene(self): def writeReferences(self): - - #pbarSimu = tqdm(total=self.steps) - #pbarSimu.set_description("Simulate: " + self.fileScenePath) + pbarSimu = tqdm(total=self.steps) + pbarSimu.set_description("Simulate: " + self.fileScenePath) nbrMeca = len(self.mecaObjs) numpyData = [] # List @@ -164,18 +163,26 @@ def writeReferences(self): mecaDofs = {} numpyData.append(mecaDofs) + counterStep = 0 + moduloStep = (self.steps-1) / self.dumpNumberStep + + # export rest position: + for mecaId in range(0, nbrMeca): + numpyData[mecaId][0.0] = np.copy(self.mecaObjs[mecaId].position.value) + for step in range(0, self.steps): Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) - if (counterStep == 499): + #print("step: " + str(step) + " | counterStep: " + str(counterStep) + " | moduloStep: " + str(moduloStep) + " | dt: " + str(self.rootNode.dt.value*(step))) + if (counterStep >= moduloStep or step == self.steps - 1): for mecaId in range(0, nbrMeca): numpyData[mecaId][self.rootNode.dt.value*(step)] = np.copy(self.mecaObjs[mecaId].position.value) counterStep = 0 counterStep = counterStep + 1 - #pbarSimu.update(1) - #pbarSimu.close() + pbarSimu.update(1) + pbarSimu.close() for mecaId in range(0, nbrMeca): #for key in numpyData[mecaId]: @@ -258,8 +265,8 @@ def processFile(self): continue - if (len(values) < 4): - print ("line read has more than 5 arguments: " + str(len(values)) + " -> " + line) + if (len(values) != 5): + print ("line read has not 5 arguments: " + str(len(values)) + " -> " + line) continue fullFilePath = os.path.join(self.fileDir, values[0]) @@ -267,8 +274,6 @@ def processFile(self): if (len(values) == 5): sceneData = RegressionSceneData(fullFilePath, fullRefFilePath, values[1], values[2], values[3], values[4]) - elif (len(values) == 4): - sceneData = RegressionSceneData(fullFilePath, fullRefFilePath, values[1], values[2], values[3], False) #sceneData.printInfo() self.scenes.append(sceneData) @@ -284,12 +289,12 @@ def writeReferences(self, idScene, printLog = False): def writeAllReferences(self): nbrScenes = len(self.scenes) - #pbarScenes = tqdm(total=nbrScenes) - #pbarScenes.set_description("Write all scenes from: " + self.filePath) + pbarScenes = tqdm(total=nbrScenes) + pbarScenes.set_description("Write all scenes from: " + self.filePath) for i in range(0, nbrScenes): self.writeReferences(i) - #pbarScenes.update(1) - #pbarScenes.close() + pbarScenes.update(1) + pbarScenes.close() def compareReferences(self, idScene): @@ -327,12 +332,12 @@ def writeSetsReferences(self, idSet = 0): def writeAllSetsReferences(self): nbrSets = len(self.sceneSets) - #pbarSets = tqdm(total=nbrSets) - #pbarSets.set_description("Write All sets") + pbarSets = tqdm(total=nbrSets) + pbarSets.set_description("Write All sets") for i in range(0, nbrSets): self.writeSetsReferences(i) - #pbarSets.update(1) - #pbarSets.close() + pbarSets.update(1) + pbarSets.close() def compareSetsReferences(self, idSet = 0): From 8c25afe0db323e550cd00d7f187d14992331e0c7 Mon Sep 17 00:00:00 2001 From: epernod Date: Mon, 19 Aug 2024 17:12:39 +0200 Subject: [PATCH 13/28] Fix comparison pipeline and add number of tested scene --- new_regression.py | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/new_regression.py b/new_regression.py index bad7790..1730443 100644 --- a/new_regression.py +++ b/new_regression.py @@ -219,11 +219,9 @@ def compareReferences(self): print("### Found same time: " + str(keyframes[frameStep])) for mecaId in range(0, nbrMeca): - #numpyData[mecaId][self.rootNode.dt.value*(step)] = np.copy(self.mecaObjs[mecaId].position.value) - print(self.mecaObjs[mecaId].position.value[820]) mecaDofs = np.copy(self.mecaObjs[mecaId].position.value) dataRef = np.asarray(numpyData[mecaId][str(keyframes[frameStep])]) - mecaDofs - print(dataRef[820]) + dist = np.linalg.norm(dataRef) print("dist: " + str(dist)) @@ -291,10 +289,13 @@ def writeAllReferences(self): nbrScenes = len(self.scenes) pbarScenes = tqdm(total=nbrScenes) pbarScenes.set_description("Write all scenes from: " + self.filePath) + for i in range(0, nbrScenes): self.writeReferences(i) pbarScenes.update(1) pbarScenes.close() + + return nbrScenes def compareReferences(self, idScene): @@ -305,10 +306,13 @@ def compareAllReferences(self): nbrScenes = len(self.scenes) pbarScenes = tqdm(total=nbrScenes) pbarScenes.set_description("Compare all scenes from: " + self.filePath) + for i in range(0, nbrScenes): self.compareReferences(i) pbarScenes.update(1) pbarScenes.close() + + return nbrScenes @@ -328,30 +332,37 @@ def __init__(self, inputFolder): def writeSetsReferences(self, idSet = 0): sceneList = self.sceneSets[idSet] - sceneList.writeAllReferences() + nbrScenes = sceneList.writeAllReferences() + return nbrScenes def writeAllSetsReferences(self): nbrSets = len(self.sceneSets) pbarSets = tqdm(total=nbrSets) pbarSets.set_description("Write All sets") + + nbrScenes = 0 for i in range(0, nbrSets): - self.writeSetsReferences(i) + nbrScenes = nbrScenes + self.writeSetsReferences(i) pbarSets.update(1) pbarSets.close() + return nbrScenes def compareSetsReferences(self, idSet = 0): sceneList = self.sceneSets[idSet] - sceneList.compareAllReferences() + nbrScenes = sceneList.compareAllReferences() + return nbrScenes def compareAllSetsReferences(self): nbrSets = len(self.sceneSets) pbarSets = tqdm(total=nbrSets) pbarSets.set_description("Compare All sets") + nbrScenes = 0 for i in range(0, nbrSets): - self.compareSetsReferences(i) + nbrScenes = nbrScenes + self.compareSetsReferences(i) pbarSets.update(1) pbarSets.close() + return nbrScenes @@ -394,11 +405,13 @@ def parse_args(): SofaRuntime.importPlugin("SofaPython3") print ("### Number of sets: " + str(len(regProg.sceneSets))) - if (args.writeMode): - regProg.writeAllSetsReferences() + nbrScenes = 0 + if (args.writeMode is True): + nbrScenes = regProg.writeAllSetsReferences() else: - regProg.compareAllSetsReferences(0) + nbrScenes = regProg.compareAllSetsReferences() print ("### Number of sets Done: " + str(len(regProg.sceneSets))) + print ("### Number of scenes Done: " + str(nbrScenes)) sys.exit() From 33c8ed2222bb5a6e4299c7e9425afa8bbc88b385 Mon Sep 17 00:00:00 2001 From: epernod Date: Mon, 19 Aug 2024 20:06:46 +0200 Subject: [PATCH 14/28] Fix compare mode and store the total error and errorByDofs --- new_regression.py | 97 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 27 deletions(-) diff --git a/new_regression.py b/new_regression.py index 1730443..7893e32 100644 --- a/new_regression.py +++ b/new_regression.py @@ -88,7 +88,7 @@ def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1 """ self.fileScenePath = fileScenePath self.fileRefPath = fileRefPath - self.steps = int(steps) + 1 + self.steps = int(steps) self.epsilon = float(epsilon) self.mecaInMapping = mecaInMapping self.dumpNumberStep = int(dumpNumberStep) @@ -96,6 +96,9 @@ def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1 self.fileNames = [] self.mins = [] self.maxs = [] + self.totalError = [] + self.errorByDof = [] + self.nbrTestedFrame = 0 def printInfo(self): print("Test scene: " + self.fileScenePath + " vs " + self.fileRefPath + " using: " + self.steps @@ -165,22 +168,19 @@ def writeReferences(self): counterStep = 0 - moduloStep = (self.steps-1) / self.dumpNumberStep + moduloStep = (self.steps) / self.dumpNumberStep - # export rest position: - for mecaId in range(0, nbrMeca): - numpyData[mecaId][0.0] = np.copy(self.mecaObjs[mecaId].position.value) - - for step in range(0, self.steps): - Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) - - #print("step: " + str(step) + " | counterStep: " + str(counterStep) + " | moduloStep: " + str(moduloStep) + " | dt: " + str(self.rootNode.dt.value*(step))) - if (counterStep >= moduloStep or step == self.steps - 1): + for step in range(0, self.steps + 1): + # export rest position, final position + modulo steps: + if (step == 0 or counterStep >= moduloStep or step == self.steps): + #print("step: " + str(step) + " | counterStep: " + str(counterStep) + " | moduloStep: " + str(moduloStep) + " | dt: " + str(self.rootNode.dt.value*(step))) for mecaId in range(0, nbrMeca): numpyData[mecaId][self.rootNode.dt.value*(step)] = np.copy(self.mecaObjs[mecaId].position.value) counterStep = 0 + Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) counterStep = counterStep + 1 + pbarSimu.update(1) pbarSimu.close() @@ -200,6 +200,9 @@ def compareReferences(self): nbrMeca = len(self.mecaObjs) numpyData = [] # List keyframes = [] + self.totalError = [] + self.errorByDof = [] + for mecaId in range(0, nbrMeca): with gzip.open(self.fileNames[mecaId], 'r') as zipfile: decodedArray = json.loads(zipfile.read().decode('utf-8')) @@ -208,30 +211,49 @@ def compareReferences(self): if (mecaId is 0): for key in decodedArray: keyframes.append(float(key)) + + self.totalError.append(0.0) + self.errorByDof.append(0.0) + frameStep = 0 - nbrFrames = len(keyframes) - for step in range(0, self.steps): - Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) + nbrFrames = len(keyframes) + self.nbrTestedFrame = 0 + for step in range(0, self.steps + 1): simuTime = self.rootNode.dt.value*(step) - #print ("time: " + str(simuTime)) - if (simuTime == keyframes[frameStep]): - print("### Found same time: " + str(keyframes[frameStep])) + if (simuTime == keyframes[frameStep]): for mecaId in range(0, nbrMeca): mecaDofs = np.copy(self.mecaObjs[mecaId].position.value) dataRef = np.asarray(numpyData[mecaId][str(keyframes[frameStep])]) - mecaDofs - dist = np.linalg.norm(dataRef) - print("dist: " + str(dist)) + # Compute total distance between the 2 sets + fullDist = np.linalg.norm(dataRef) + errorByDof = fullDist / float(dataRef.size) + + #print (str(step) + " | fullDist: " + str(fullDist) + " | errorByDof: " + str(errorByDof) + " | nbrDofs: " + str(dataRef.size)) + self.totalError[mecaId] = self.totalError[mecaId] + fullDist + self.errorByDof[mecaId] = self.errorByDof[mecaId] + errorByDof frameStep = frameStep + 1 + self.nbrTestedFrame = self.nbrTestedFrame + 1 + + # security exit if simulation steps exceed nbrFrames if (frameStep == nbrFrames): - print ("exit comparison") - return + break + + Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) pbarSimu.update(1) pbarSimu.close() + + for mecaId in range(0, nbrMeca): + if (self.totalError[mecaId] > self.epsilon): + print("### " + self.fileScenePath + " | Total error exceed threshold for at least one MechanicalObject: " + str(self.totalError) + " Error by Dofs: " + str(self.errorByDof)) + return False + + print ("### " + self.fileScenePath + " | Number of key frames compared without error: " + str(self.nbrTestedFrame)) + return True class RegressionSceneList: @@ -239,6 +261,14 @@ def __init__(self, filePath): self.filePath = filePath self.fileDir = os.path.dirname(filePath) self.scenes = [] # List + self.nbrErrors = 0 + + + def getNbrScenes(self): + return len(self.scenes) + + def getNbrErrors(self): + return self.nbrErrors def processFile(self): print("### Processing Regression file: " + self.filePath) @@ -300,7 +330,9 @@ def writeAllReferences(self): def compareReferences(self, idScene): self.scenes[idScene].loadScene() - self.scenes[idScene].compareReferences() + result = self.scenes[idScene].compareReferences() + if (result == False): + self.nbrErrors = self.nbrErrors + 1 def compareAllReferences(self): nbrScenes = len(self.scenes) @@ -330,6 +362,13 @@ def __init__(self, inputFolder): sceneList.processFile() self.sceneSets.append(sceneList) + def nbrErrorInSets(self): + nbrErrors = 0 + nbrSets = len(self.sceneSets) + for sceneList in self.sceneSets: + nbrErrors = nbrErrors + sceneList.getNbrErrors() + return nbrErrors + def writeSetsReferences(self, idSet = 0): sceneList = self.sceneSets[idSet] nbrScenes = sceneList.writeAllReferences() @@ -384,9 +423,9 @@ def parse_args(): parser.add_argument( "--writeRef", - dest="writeMode", - default=False, - help='If true, will generate new reference files' + dest="writeMode", + help='If true, will generate new reference files', + type=int ) args = parser.parse_args() @@ -404,14 +443,18 @@ def parse_args(): regProg = RegressionProgram(args.input) SofaRuntime.importPlugin("SofaPython3") - print ("### Number of sets: " + str(len(regProg.sceneSets))) nbrScenes = 0 - if (args.writeMode is True): + writeMode = bool(args.writeMode) + + if writeMode is True: nbrScenes = regProg.writeAllSetsReferences() else: nbrScenes = regProg.compareAllSetsReferences() + print ("### Number of sets Done: " + str(len(regProg.sceneSets))) print ("### Number of scenes Done: " + str(nbrScenes)) + if writeMode is False: + print ("### Number of scenes failed: " + str(regProg.nbrErrorInSets())) sys.exit() From 6d546aa581ad764b6dc9ca6ddfb04c802a06cb8b Mon Sep 17 00:00:00 2001 From: epernod Date: Wed, 21 Aug 2024 12:06:06 +0200 Subject: [PATCH 15/28] Add method to print results at end and remove intermediate prints --- new_regression.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/new_regression.py b/new_regression.py index 7893e32..a733cf1 100644 --- a/new_regression.py +++ b/new_regression.py @@ -99,10 +99,19 @@ def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1 self.totalError = [] self.errorByDof = [] self.nbrTestedFrame = 0 + self.regressionFailed = False def printInfo(self): print("Test scene: " + self.fileScenePath + " vs " + self.fileRefPath + " using: " + self.steps + " " + self.epsilon) + + def logErrors(self): + if self.regressionFailed is True: + print("### Failed: " + self.fileScenePath) + print(" ### Total Error per MechanicalObject: " + str(self.totalError)) + print(" ### Error by Dofs: " + str(self.errorByDof)) + else: + print ("### Success: " + self.fileScenePath + " | Number of key frames compared without error: " + str(self.nbrTestedFrame)) def printMecaObjs(self): @@ -231,7 +240,7 @@ def compareReferences(self): fullDist = np.linalg.norm(dataRef) errorByDof = fullDist / float(dataRef.size) - #print (str(step) + " | fullDist: " + str(fullDist) + " | errorByDof: " + str(errorByDof) + " | nbrDofs: " + str(dataRef.size)) + #print (str(step) + "| " + self.mecaObjs[mecaId].name.value + " | fullDist: " + str(fullDist) + " | errorByDof: " + str(errorByDof) + " | nbrDofs: " + str(dataRef.size)) self.totalError[mecaId] = self.totalError[mecaId] + fullDist self.errorByDof[mecaId] = self.errorByDof[mecaId] + errorByDof @@ -249,10 +258,9 @@ def compareReferences(self): for mecaId in range(0, nbrMeca): if (self.totalError[mecaId] > self.epsilon): - print("### " + self.fileScenePath + " | Total error exceed threshold for at least one MechanicalObject: " + str(self.totalError) + " Error by Dofs: " + str(self.errorByDof)) + self.regressionFailed = True return False - print ("### " + self.fileScenePath + " | Number of key frames compared without error: " + str(self.nbrTestedFrame)) return True @@ -269,10 +277,12 @@ def getNbrScenes(self): def getNbrErrors(self): return self.nbrErrors + + def logScenesErrors(self): + for scene in self.scenes: + scene.logErrors() def processFile(self): - print("### Processing Regression file: " + self.filePath) - with open(self.filePath, 'r') as thefile: data = thefile.readlines() thefile.close() @@ -305,8 +315,7 @@ def processFile(self): #sceneData.printInfo() self.scenes.append(sceneData) - - print("## nbrScenes: " + str(len(self.scenes))) + def writeReferences(self, idScene, printLog = False): self.scenes[idScene].loadScene() @@ -364,10 +373,13 @@ def __init__(self, inputFolder): def nbrErrorInSets(self): nbrErrors = 0 - nbrSets = len(self.sceneSets) for sceneList in self.sceneSets: nbrErrors = nbrErrors + sceneList.getNbrErrors() return nbrErrors + + def logErrorsInSets(self): + for sceneList in self.sceneSets: + sceneList.logScenesErrors() def writeSetsReferences(self, idSet = 0): sceneList = self.sceneSets[idSet] @@ -455,6 +467,8 @@ def parse_args(): print ("### Number of scenes Done: " + str(nbrScenes)) if writeMode is False: print ("### Number of scenes failed: " + str(regProg.nbrErrorInSets())) + #np.set_printoptions(precision=8) + regProg.logErrorsInSets() sys.exit() From c3cd349ec8028d85ef7539c589e7354d30096fbd Mon Sep 17 00:00:00 2001 From: epernod Date: Wed, 11 Sep 2024 21:14:02 +0200 Subject: [PATCH 16/28] Split new script into 3 files --- new_regression.py | 370 ++------------------------------ tools/RegressionSceneData.py | 263 +++++++++++++++++++++++ tools/RegressionSceneParsing.py | 101 +++++++++ 3 files changed, 387 insertions(+), 347 deletions(-) create mode 100644 tools/RegressionSceneData.py create mode 100644 tools/RegressionSceneParsing.py diff --git a/new_regression.py b/new_regression.py index a733cf1..8d9abf2 100644 --- a/new_regression.py +++ b/new_regression.py @@ -1,360 +1,28 @@ import glob, os import argparse import sys -import Sofa -import SofaRuntime import numpy as np from tqdm import tqdm -from json import JSONEncoder -import json -import gzip - -debugInfo = True - -def isSimulated(node): - if (node.hasODESolver()): - return True - - # if no Solver in current node, check parent nodes - for parent in node.parents: - solverFound = isSimulated(parent) - if (solverFound): - return True - - return False - - -class NumpyArrayEncoder(JSONEncoder): - def default(self, obj): - if isinstance(obj, np.ndarray): - return obj.tolist() - return JSONEncoder.default(self, obj) - -def exportJson(): - - numpyArrayOne = np.array([[11 ,22, 33], [44, 55, 66], [77, 88, 99]]) - numpyArrayTwo = np.array([[51, 61, 91], [121 ,118, 127]]) - - # Serialization - numpyData = {"arrayOne": numpyArrayOne, "arrayTwo": numpyArrayTwo} - print("serialize NumPy array into JSON and write into a file") - with gzip.open("numpyData.json.gz", 'w') as zipfile: - for key in numpyData: - print(numpyData[key]) - - #write_file.write(json.dumps(numpyData, cls=NumpyArrayEncoder, indent=4)) - #res = json.dumps(numpyData, cls=NumpyArrayEncoder, indent=4) - #print(res) - #json.dump(numpyData, zipfile, cls=NumpyArrayEncoder) - zipfile.write(json.dumps(numpyData, cls=NumpyArrayEncoder).encode('utf-8')) - - print("Done writing serialized NumPy array into file") - -def readJson(): - # Deserialization - print("Started Reading JSON file") - with gzip.open("numpyData.json.gz", 'r') as zipfile: - - #with open("numpyData.json", "r") as read_file: - print("Converting JSON encoded data into Numpy array") - decodedArray = json.loads(zipfile.read().decode('utf-8')) - #decodedArray = json.load(zipfile) - - finalNumpyArrayOne = np.asarray(decodedArray["arrayOne"]) - print("NumPy Array One") - print(finalNumpyArrayOne) - finalNumpyArrayTwo = np.asarray(decodedArray["arrayTwo"]) - print("NumPy Array Two") - print(finalNumpyArrayTwo) - - - -class RegressionSceneData: - def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1000, - epsilon = 0.0001, mecaInMapping = True, dumpNumberStep = 1): - """ - /// Path to the file scene to test - std::string m_fileScenePath; - /// Path to the reference file corresponding to the scene to test - std::string m_fileRefPath; - /// Number of step to perform - unsigned int m_steps; - /// Threshold value for dof position comparison - double m_epsilon; - /// Option to test mechanicalObject in Node containing a Mapping (true will test them) - bool m_mecaInMapping; - /// Option to compare mechanicalObject dof position at each timestep - bool m_dumpNumberStep; - """ - self.fileScenePath = fileScenePath - self.fileRefPath = fileRefPath - self.steps = int(steps) - self.epsilon = float(epsilon) - self.mecaInMapping = mecaInMapping - self.dumpNumberStep = int(dumpNumberStep) - self.mecaObjs = [] - self.fileNames = [] - self.mins = [] - self.maxs = [] - self.totalError = [] - self.errorByDof = [] - self.nbrTestedFrame = 0 - self.regressionFailed = False - def printInfo(self): - print("Test scene: " + self.fileScenePath + " vs " + self.fileRefPath + " using: " + self.steps - + " " + self.epsilon) - - def logErrors(self): - if self.regressionFailed is True: - print("### Failed: " + self.fileScenePath) - print(" ### Total Error per MechanicalObject: " + str(self.totalError)) - print(" ### Error by Dofs: " + str(self.errorByDof)) - else: - print ("### Success: " + self.fileScenePath + " | Number of key frames compared without error: " + str(self.nbrTestedFrame)) - - - def printMecaObjs(self): - print ("# Nbr Meca: " + str(len(self.mecaObjs))) - counter = 0 - for mecaObj in self.mecaObjs: - filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" - counter = counter+1 - print ("# File attached: " + filename) - - - def parseNode(self, node, level = 0): - for child in node.children: - mstate = child.getMechanicalState() - if (mstate): - if (isSimulated(child)): - self.mecaObjs.append(mstate) - - self.parseNode(child, level+1) - - - def addCompareState(self): - counter = 0 - for mecaObj in self.mecaObjs: - _filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" - - mecaObj.getContext().addObject('CompareState', filename=_filename) - counter = counter+1 +sofa_root = "C:\\projects\\sofa-build" +sofapython3_path = sofa_root + "\\lib\\python3\\site-packages" +sofa_build_configuration = "Release" - def addWriteState(self): - counter = 0 - for mecaObj in self.mecaObjs: - _filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" - - mecaObj.getContext().addObject('WriteState', filename=_filename) - counter = counter+1 - +# Set env +os.environ["SOFA_ROOT"] = sofa_root +os.environ["PYTHONPATH"] = sofapython3_path +os.environ["SOFA_BUILD_CONFIGURATION"] = sofa_build_configuration +sys.path.append(sofapython3_path) - def loadScene(self): - self.rootNode = Sofa.Simulation.load(self.fileScenePath) - Sofa.Simulation.init(self.rootNode) - - # prepare ref files per mecaObjs: - self.parseNode(self.rootNode, 0) - counter = 0 - for mecaObj in self.mecaObjs: - _filename = self.fileRefPath + ".reference_mstate_" + str(counter) + "_" + mecaObj.name.value + ".json.gz" - self.fileNames.append(_filename) - counter = counter+1 - - - - def writeReferences(self): - pbarSimu = tqdm(total=self.steps) - pbarSimu.set_description("Simulate: " + self.fileScenePath) - - nbrMeca = len(self.mecaObjs) - numpyData = [] # List - for mecaId in range(0, nbrMeca): - mecaDofs = {} - numpyData.append(mecaDofs) - - - counterStep = 0 - moduloStep = (self.steps) / self.dumpNumberStep - - for step in range(0, self.steps + 1): - # export rest position, final position + modulo steps: - if (step == 0 or counterStep >= moduloStep or step == self.steps): - #print("step: " + str(step) + " | counterStep: " + str(counterStep) + " | moduloStep: " + str(moduloStep) + " | dt: " + str(self.rootNode.dt.value*(step))) - for mecaId in range(0, nbrMeca): - numpyData[mecaId][self.rootNode.dt.value*(step)] = np.copy(self.mecaObjs[mecaId].position.value) - counterStep = 0 - - Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) - counterStep = counterStep + 1 - - pbarSimu.update(1) - pbarSimu.close() - - for mecaId in range(0, nbrMeca): - #for key in numpyData[mecaId]: - # print("key: %s , value: %s" % (key, numpyData[mecaId][key][820])) - with gzip.open(self.fileNames[mecaId], "w") as write_file: - write_file.write(json.dumps(numpyData[mecaId], cls=NumpyArrayEncoder).encode('utf-8')) - - Sofa.Simulation.unload(self.rootNode) - - - def compareReferences(self): - pbarSimu = tqdm(total=float(self.steps)) - pbarSimu.set_description("compareReferences: " + self.fileScenePath) - - nbrMeca = len(self.mecaObjs) - numpyData = [] # List - keyframes = [] - self.totalError = [] - self.errorByDof = [] - - for mecaId in range(0, nbrMeca): - with gzip.open(self.fileNames[mecaId], 'r') as zipfile: - decodedArray = json.loads(zipfile.read().decode('utf-8')) - numpyData.append(decodedArray) - - if (mecaId is 0): - for key in decodedArray: - keyframes.append(float(key)) - - self.totalError.append(0.0) - self.errorByDof.append(0.0) - - - frameStep = 0 - nbrFrames = len(keyframes) - self.nbrTestedFrame = 0 - for step in range(0, self.steps + 1): - simuTime = self.rootNode.dt.value*(step) - - if (simuTime == keyframes[frameStep]): - for mecaId in range(0, nbrMeca): - mecaDofs = np.copy(self.mecaObjs[mecaId].position.value) - dataRef = np.asarray(numpyData[mecaId][str(keyframes[frameStep])]) - mecaDofs - - # Compute total distance between the 2 sets - fullDist = np.linalg.norm(dataRef) - errorByDof = fullDist / float(dataRef.size) - - #print (str(step) + "| " + self.mecaObjs[mecaId].name.value + " | fullDist: " + str(fullDist) + " | errorByDof: " + str(errorByDof) + " | nbrDofs: " + str(dataRef.size)) - self.totalError[mecaId] = self.totalError[mecaId] + fullDist - self.errorByDof[mecaId] = self.errorByDof[mecaId] + errorByDof - - frameStep = frameStep + 1 - self.nbrTestedFrame = self.nbrTestedFrame + 1 - - # security exit if simulation steps exceed nbrFrames - if (frameStep == nbrFrames): - break - - Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) - - pbarSimu.update(1) - pbarSimu.close() - - for mecaId in range(0, nbrMeca): - if (self.totalError[mecaId] > self.epsilon): - self.regressionFailed = True - return False - - return True - - -class RegressionSceneList: - def __init__(self, filePath): - self.filePath = filePath - self.fileDir = os.path.dirname(filePath) - self.scenes = [] # List - self.nbrErrors = 0 - - - def getNbrScenes(self): - return len(self.scenes) - - def getNbrErrors(self): - return self.nbrErrors - - def logScenesErrors(self): - for scene in self.scenes: - scene.logErrors() - - def processFile(self): - with open(self.filePath, 'r') as thefile: - data = thefile.readlines() - thefile.close() - - count = 0 - for idx, line in enumerate(data): - if (line[0] == "#"): - continue - - values = line.split() - if (len(values) == 0): - continue - - if (count == 0): - self.refDirPath = os.path.join(self.fileDir, values[0]) - self.refDirPath = os.path.abspath(self.refDirPath) - count = count + 1 - continue - - - if (len(values) != 5): - print ("line read has not 5 arguments: " + str(len(values)) + " -> " + line) - continue - - fullFilePath = os.path.join(self.fileDir, values[0]) - fullRefFilePath = os.path.join(self.refDirPath, values[0]) - - if (len(values) == 5): - sceneData = RegressionSceneData(fullFilePath, fullRefFilePath, values[1], values[2], values[3], values[4]) - - #sceneData.printInfo() - self.scenes.append(sceneData) - - - def writeReferences(self, idScene, printLog = False): - self.scenes[idScene].loadScene() - if (printLog is True): - self.scenes[idScene].printMecaObjs() - - self.scenes[idScene].writeReferences() - - def writeAllReferences(self): - nbrScenes = len(self.scenes) - pbarScenes = tqdm(total=nbrScenes) - pbarScenes.set_description("Write all scenes from: " + self.filePath) - - for i in range(0, nbrScenes): - self.writeReferences(i) - pbarScenes.update(1) - pbarScenes.close() - - return nbrScenes +import Sofa +import SofaRuntime - def compareReferences(self, idScene): - self.scenes[idScene].loadScene() - result = self.scenes[idScene].compareReferences() - if (result == False): - self.nbrErrors = self.nbrErrors + 1 - - def compareAllReferences(self): - nbrScenes = len(self.scenes) - pbarScenes = tqdm(total=nbrScenes) - pbarScenes.set_description("Compare all scenes from: " + self.filePath) - - for i in range(0, nbrScenes): - self.compareReferences(i) - pbarScenes.update(1) - pbarScenes.close() - - return nbrScenes - +dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), './tools') +sys.path.append(os.path.abspath(dir)) +import RegressionSceneData +import RegressionSceneParsing class RegressionProgram: @@ -366,7 +34,7 @@ def __init__(self, inputFolder): if file.endswith(".regression-tests"): filePath = os.path.join(root, file) - sceneList = RegressionSceneList(filePath) + sceneList = RegressionSceneParsing.RegressionSceneList(filePath) sceneList.processFile() self.sceneSets.append(sceneList) @@ -446,6 +114,13 @@ def parse_args(): +def loadGui(root): + Sofa.Gui.GUIManager.Init("myscene", "qglviewer") + Sofa.Gui.GUIManager.createGUI(root, __file__) + Sofa.Gui.GUIManager.SetDimension(1080, 1080) + Sofa.Gui.GUIManager.MainLoop(root) + Sofa.Gui.GUIManager.closeGUI() + if __name__ == '__main__': @@ -453,6 +128,7 @@ def parse_args(): args = parse_args() # 2- Process file regProg = RegressionProgram(args.input) + #SofaRuntime.disable_messages() SofaRuntime.importPlugin("SofaPython3") nbrScenes = 0 diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py new file mode 100644 index 0000000..19edcc2 --- /dev/null +++ b/tools/RegressionSceneData.py @@ -0,0 +1,263 @@ +from tqdm import tqdm +import json +from json import JSONEncoder +import numpy as np +import gzip + +import Sofa + +debugInfo = False + +def isSimulated(node): + if (node.hasODESolver()): + return True + + # if no Solver in current node, check parent nodes + for parent in node.parents: + solverFound = isSimulated(parent) + if (solverFound): + return True + + return False + + +def exportJson(): + + numpyArrayOne = np.array([[11 ,22, 33], [44, 55, 66], [77, 88, 99]]) + numpyArrayTwo = np.array([[51, 61, 91], [121 ,118, 127]]) + + # Serialization + numpyData = {"arrayOne": numpyArrayOne, "arrayTwo": numpyArrayTwo} + print("serialize NumPy array into JSON and write into a file") + with gzip.open("numpyData.json.gz", 'w') as zipfile: + for key in numpyData: + print(numpyData[key]) + + #write_file.write(json.dumps(numpyData, cls=NumpyArrayEncoder, indent=4)) + #res = json.dumps(numpyData, cls=NumpyArrayEncoder, indent=4) + #print(res) + #json.dump(numpyData, zipfile, cls=NumpyArrayEncoder) + zipfile.write(json.dumps(numpyData, cls=NumpyArrayEncoder).encode('utf-8')) + + print("Done writing serialized NumPy array into file") + +def readJson(): + # Deserialization + print("Started Reading JSON file") + with gzip.open("numpyData.json.gz", 'r') as zipfile: + + #with open("numpyData.json", "r") as read_file: + print("Converting JSON encoded data into Numpy array") + decodedArray = json.loads(zipfile.read().decode('utf-8')) + #decodedArray = json.load(zipfile) + + finalNumpyArrayOne = np.asarray(decodedArray["arrayOne"]) + print("NumPy Array One") + print(finalNumpyArrayOne) + finalNumpyArrayTwo = np.asarray(decodedArray["arrayTwo"]) + print("NumPy Array Two") + print(finalNumpyArrayTwo) + + +class NumpyArrayEncoder(JSONEncoder): + def default(self, obj): + if isinstance(obj, np.ndarray): + return obj.tolist() + return JSONEncoder.default(self, obj) + + +class RegressionSceneData: + def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1000, + epsilon = 0.0001, mecaInMapping = True, dumpNumberStep = 1): + """ + /// Path to the file scene to test + std::string m_fileScenePath; + /// Path to the reference file corresponding to the scene to test + std::string m_fileRefPath; + /// Number of step to perform + unsigned int m_steps; + /// Threshold value for dof position comparison + double m_epsilon; + /// Option to test mechanicalObject in Node containing a Mapping (true will test them) + bool m_mecaInMapping; + /// Option to compare mechanicalObject dof position at each timestep + bool m_dumpNumberStep; + """ + self.fileScenePath = fileScenePath + self.fileRefPath = fileRefPath + self.steps = int(steps) + self.epsilon = float(epsilon) + self.mecaInMapping = mecaInMapping + self.dumpNumberStep = int(dumpNumberStep) + self.mecaObjs = [] + self.fileNames = [] + self.mins = [] + self.maxs = [] + self.totalError = [] + self.errorByDof = [] + self.nbrTestedFrame = 0 + self.regressionFailed = False + + def printInfo(self): + print("Test scene: " + self.fileScenePath + " vs " + self.fileRefPath + " using: " + self.steps + + " " + self.epsilon) + + def logErrors(self): + if self.regressionFailed is True: + print("### Failed: " + self.fileScenePath) + print(" ### Total Error per MechanicalObject: " + str(self.totalError)) + print(" ### Error by Dofs: " + str(self.errorByDof)) + else: + print ("### Success: " + self.fileScenePath + " | Number of key frames compared without error: " + str(self.nbrTestedFrame)) + + + def printMecaObjs(self): + print ("# Nbr Meca: " + str(len(self.mecaObjs))) + counter = 0 + for mecaObj in self.mecaObjs: + filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" + counter = counter+1 + print ("# File attached: " + filename) + + + def parseNode(self, node, level = 0): + for child in node.children: + mstate = child.getMechanicalState() + if (mstate): + if (isSimulated(child)): + self.mecaObjs.append(mstate) + + self.parseNode(child, level+1) + + + def addCompareState(self): + counter = 0 + for mecaObj in self.mecaObjs: + _filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" + + mecaObj.getContext().addObject('CompareState', filename=_filename) + counter = counter+1 + + + def addWriteState(self): + counter = 0 + for mecaObj in self.mecaObjs: + _filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" + + mecaObj.getContext().addObject('WriteState', filename=_filename) + counter = counter+1 + + + def loadScene(self): + self.rootNode = Sofa.Simulation.load(self.fileScenePath) + Sofa.Simulation.init(self.rootNode) + + # prepare ref files per mecaObjs: + self.parseNode(self.rootNode, 0) + counter = 0 + for mecaObj in self.mecaObjs: + _filename = self.fileRefPath + ".reference_mstate_" + str(counter) + "_" + mecaObj.name.value + ".json.gz" + self.fileNames.append(_filename) + counter = counter+1 + + + + def writeReferences(self): + pbarSimu = tqdm(total=self.steps) + pbarSimu.set_description("Simulate: " + self.fileScenePath) + + nbrMeca = len(self.mecaObjs) + numpyData = [] # List + for mecaId in range(0, nbrMeca): + mecaDofs = {} + numpyData.append(mecaDofs) + + + counterStep = 0 + moduloStep = (self.steps) / self.dumpNumberStep + + for step in range(0, self.steps + 1): + # export rest position, final position + modulo steps: + if (step == 0 or counterStep >= moduloStep or step == self.steps): + #print("step: " + str(step) + " | counterStep: " + str(counterStep) + " | moduloStep: " + str(moduloStep) + " | dt: " + str(self.rootNode.dt.value*(step))) + for mecaId in range(0, nbrMeca): + numpyData[mecaId][self.rootNode.dt.value*(step)] = np.copy(self.mecaObjs[mecaId].position.value) + counterStep = 0 + + Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) + counterStep = counterStep + 1 + + pbarSimu.update(1) + pbarSimu.close() + + for mecaId in range(0, nbrMeca): + #for key in numpyData[mecaId]: + # print("key: %s , value: %s" % (key, numpyData[mecaId][key][820])) + with gzip.open(self.fileNames[mecaId], "w") as write_file: + write_file.write(json.dumps(numpyData[mecaId], cls=NumpyArrayEncoder).encode('utf-8')) + + Sofa.Simulation.unload(self.rootNode) + + + def compareReferences(self): + pbarSimu = tqdm(total=float(self.steps)) + pbarSimu.set_description("compareReferences: " + self.fileScenePath) + + nbrMeca = len(self.mecaObjs) + numpyData = [] # List + keyframes = [] + self.totalError = [] + self.errorByDof = [] + + for mecaId in range(0, nbrMeca): + with gzip.open(self.fileNames[mecaId], 'r') as zipfile: + decodedArray = json.loads(zipfile.read().decode('utf-8')) + numpyData.append(decodedArray) + + if (mecaId is 0): + for key in decodedArray: + keyframes.append(float(key)) + + self.totalError.append(0.0) + self.errorByDof.append(0.0) + + + frameStep = 0 + nbrFrames = len(keyframes) + self.nbrTestedFrame = 0 + for step in range(0, self.steps + 1): + simuTime = self.rootNode.dt.value*(step) + + if (simuTime == keyframes[frameStep]): + for mecaId in range(0, nbrMeca): + mecaDofs = np.copy(self.mecaObjs[mecaId].position.value) + dataRef = np.asarray(numpyData[mecaId][str(keyframes[frameStep])]) - mecaDofs + + # Compute total distance between the 2 sets + fullDist = np.linalg.norm(dataRef) + errorByDof = fullDist / float(dataRef.size) + + if (debugInfo is True): + print (str(step) + "| " + self.mecaObjs[mecaId].name.value + " | fullDist: " + str(fullDist) + " | errorByDof: " + str(errorByDof) + " | nbrDofs: " + str(dataRef.size)) + + self.totalError[mecaId] = self.totalError[mecaId] + fullDist + self.errorByDof[mecaId] = self.errorByDof[mecaId] + errorByDof + + frameStep = frameStep + 1 + self.nbrTestedFrame = self.nbrTestedFrame + 1 + + # security exit if simulation steps exceed nbrFrames + if (frameStep == nbrFrames): + break + + Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) + + pbarSimu.update(1) + pbarSimu.close() + + for mecaId in range(0, nbrMeca): + if (self.totalError[mecaId] > self.epsilon): + self.regressionFailed = True + return False + + return True diff --git a/tools/RegressionSceneParsing.py b/tools/RegressionSceneParsing.py new file mode 100644 index 0000000..771d9c4 --- /dev/null +++ b/tools/RegressionSceneParsing.py @@ -0,0 +1,101 @@ +import sys, os +import RegressionSceneData +from tqdm import tqdm + + +## This class is responsible for loading a file.regression-tests to gather the list of scene to test with all arguments +## It will provide the API to launch the tests or write refs on all scenes contained in this file +class RegressionSceneList: + def __init__(self, filePath): + """ + /// Path to the file.regression-tests containing the list of scene to tests with all arguments + std::string filePath; + """ + self.filePath = filePath + self.fileDir = os.path.dirname(filePath) + self.scenes = [] # List + self.nbrErrors = 0 + + + def getNbrScenes(self): + return len(self.scenes) + + def getNbrErrors(self): + return self.nbrErrors + + def logScenesErrors(self): + for scene in self.scenes: + scene.logErrors() + + def processFile(self): + with open(self.filePath, 'r') as thefile: + data = thefile.readlines() + thefile.close() + + count = 0 + for idx, line in enumerate(data): + if (line[0] == "#"): + continue + + values = line.split() + if (len(values) == 0): + continue + + if (count == 0): + self.refDirPath = os.path.join(self.fileDir, values[0]) + self.refDirPath = os.path.abspath(self.refDirPath) + count = count + 1 + continue + + + if (len(values) != 5): + print ("line read has not 5 arguments: " + str(len(values)) + " -> " + line) + continue + + fullFilePath = os.path.join(self.fileDir, values[0]) + fullRefFilePath = os.path.join(self.refDirPath, values[0]) + + if (len(values) == 5): + sceneData = RegressionSceneData.RegressionSceneData(fullFilePath, fullRefFilePath, values[1], values[2], values[3], values[4]) + + #sceneData.printInfo() + self.scenes.append(sceneData) + + + def writeReferences(self, idScene, printLog = False): + self.scenes[idScene].loadScene() + if (printLog is True): + self.scenes[idScene].printMecaObjs() + + self.scenes[idScene].writeReferences() + + def writeAllReferences(self): + nbrScenes = len(self.scenes) + pbarScenes = tqdm(total=nbrScenes) + pbarScenes.set_description("Write all scenes from: " + self.filePath) + + for i in range(0, nbrScenes): + self.writeReferences(i) + pbarScenes.update(1) + pbarScenes.close() + + return nbrScenes + + + def compareReferences(self, idScene): + self.scenes[idScene].loadScene() + result = self.scenes[idScene].compareReferences() + if (result == False): + self.nbrErrors = self.nbrErrors + 1 + + def compareAllReferences(self): + nbrScenes = len(self.scenes) + pbarScenes = tqdm(total=nbrScenes) + pbarScenes.set_description("Compare all scenes from: " + self.filePath) + + for i in range(0, nbrScenes): + self.compareReferences(i) + pbarScenes.update(1) + pbarScenes.close() + + return nbrScenes From edae2f650b854c6cc2210a5eb2d09541842459d6 Mon Sep 17 00:00:00 2001 From: epernod Date: Wed, 11 Sep 2024 21:41:53 +0200 Subject: [PATCH 17/28] backup work on replay mode --- new_regression.py | 23 ++++++++++++++--------- tools/RegressionSceneData.py | 13 +++++++++++++ tools/RegressionSceneParsing.py | 9 ++++++++- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/new_regression.py b/new_regression.py index 8d9abf2..adbcf36 100644 --- a/new_regression.py +++ b/new_regression.py @@ -82,6 +82,10 @@ def compareAllSetsReferences(self): pbarSets.update(1) pbarSets.close() return nbrScenes + + def replayReferences(self, idSet = 0): + sceneList = self.sceneSets[idSet] + sceneList.replayReferences(0) @@ -101,6 +105,11 @@ def parse_args(): help="Directory where to export data preprocessed", type=str) + parser.add_argument('--replay', + dest='replay', + help="test option to replay reference", + type=int) + parser.add_argument( "--writeRef", dest="writeMode", @@ -112,15 +121,6 @@ def parse_args(): return args - - -def loadGui(root): - Sofa.Gui.GUIManager.Init("myscene", "qglviewer") - Sofa.Gui.GUIManager.createGUI(root, __file__) - Sofa.Gui.GUIManager.SetDimension(1080, 1080) - Sofa.Gui.GUIManager.MainLoop(root) - Sofa.Gui.GUIManager.closeGUI() - if __name__ == '__main__': @@ -134,6 +134,11 @@ def loadGui(root): nbrScenes = 0 writeMode = bool(args.writeMode) + replay = bool(args.replay) + if replay is True: + regProg.replayReferences() + sys.exit() + if writeMode is True: nbrScenes = regProg.writeAllSetsReferences() else: diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py index 19edcc2..c59d081 100644 --- a/tools/RegressionSceneData.py +++ b/tools/RegressionSceneData.py @@ -5,6 +5,8 @@ import gzip import Sofa +import Sofa.Simulation +import Sofa.Gui debugInfo = False @@ -261,3 +263,14 @@ def compareReferences(self): return False return True + + + def replayReferences(self): + Sofa.Gui.GUIManager.Init("myscene", "qglviewer") + Sofa.Gui.GUIManager.createGUI(self.rootNode, __file__) + Sofa.Gui.GUIManager.SetDimension(1080, 1080) + Sofa.Gui.GUIManager.MainLoop(self.rootNode) + Sofa.Gui.GUIManager.closeGUI() + + + diff --git a/tools/RegressionSceneParsing.py b/tools/RegressionSceneParsing.py index 771d9c4..56beaa2 100644 --- a/tools/RegressionSceneParsing.py +++ b/tools/RegressionSceneParsing.py @@ -97,5 +97,12 @@ def compareAllReferences(self): self.compareReferences(i) pbarScenes.update(1) pbarScenes.close() - + return nbrScenes + + + def replayReferences(self, idScene): + self.scenes[idScene].loadScene() + self.scenes[idScene].replayReferences() + + From 8ca4bd3d6770074fdce43ced058ea1d1ff149cf4 Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Tue, 19 Nov 2024 11:17:38 +0900 Subject: [PATCH 18/28] fixes and usability upgrades --- new_regression.py | 34 ++++++++++++++++++++++------------ tools/RegressionSceneData.py | 2 +- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/new_regression.py b/new_regression.py index adbcf36..db9d856 100644 --- a/new_regression.py +++ b/new_regression.py @@ -2,23 +2,25 @@ import argparse import sys import numpy as np -from tqdm import tqdm +from tqdm import tqdm -sofa_root = "C:\\projects\\sofa-build" -sofapython3_path = sofa_root + "\\lib\\python3\\site-packages" -sofa_build_configuration = "Release" +if "SOFA_ROOT" not in os.environ: + sofa_real_root = "/Users/fred/Work/sofa" + sofa_root = sofa_real_root + "/build/current-ninja" + sofapython3_path = sofa_root + "/lib/python3/site-packages" + sofa_build_configuration = "Release" -# Set env -os.environ["SOFA_ROOT"] = sofa_root -os.environ["PYTHONPATH"] = sofapython3_path -os.environ["SOFA_BUILD_CONFIGURATION"] = sofa_build_configuration -sys.path.append(sofapython3_path) + os.environ["SOFA_ROOT"] = sofa_root + os.environ["SOFA_BUILD_CONFIGURATION"] = sofa_build_configuration + sys.path.append(sofapython3_path) +else: + sofapython3_path = os.environ["SOFA_ROOT"] + "/lib/python3/site-packages" + sys.path.append(sofapython3_path) import Sofa import SofaRuntime - dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), './tools') sys.path.append(os.path.abspath(dir)) import RegressionSceneData @@ -63,7 +65,9 @@ def writeAllSetsReferences(self): for i in range(0, nbrSets): nbrScenes = nbrScenes + self.writeSetsReferences(i) pbarSets.update(1) + pbarSets.close() + return nbrScenes @@ -76,11 +80,14 @@ def compareAllSetsReferences(self): nbrSets = len(self.sceneSets) pbarSets = tqdm(total=nbrSets) pbarSets.set_description("Compare All sets") + nbrScenes = 0 for i in range(0, nbrSets): nbrScenes = nbrScenes + self.compareSetsReferences(i) pbarSets.update(1) + pbarSets.close() + return nbrScenes def replayReferences(self, idSet = 0): @@ -127,7 +134,10 @@ def parse_args(): # 1- Parse arguments to get folder path args = parse_args() # 2- Process file - regProg = RegressionProgram(args.input) + if args.input is not None: + regProg = RegressionProgram(args.input) + else: + exit("Error: Argument is required ! Quitting.") #SofaRuntime.disable_messages() SofaRuntime.importPlugin("SofaPython3") @@ -153,4 +163,4 @@ def parse_args(): sys.exit() - \ No newline at end of file + diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py index c59d081..7927a8d 100644 --- a/tools/RegressionSceneData.py +++ b/tools/RegressionSceneData.py @@ -216,7 +216,7 @@ def compareReferences(self): decodedArray = json.loads(zipfile.read().decode('utf-8')) numpyData.append(decodedArray) - if (mecaId is 0): + if mecaId == 0: for key in decodedArray: keyframes.append(float(key)) From 4078d6f973057285c5dd00bcf718dc21a940fcc9 Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Mon, 23 Dec 2024 10:24:31 +0900 Subject: [PATCH 19/28] massive renaming --- new_regression.py | 149 +++++++++--------- tools/RegressionSceneData.py | 265 ++++++++++++++++---------------- tools/RegressionSceneParsing.py | 115 +++++++------- 3 files changed, 267 insertions(+), 262 deletions(-) diff --git a/new_regression.py b/new_regression.py index db9d856..5826cfc 100644 --- a/new_regression.py +++ b/new_regression.py @@ -1,7 +1,6 @@ -import glob, os +import os import argparse import sys -import numpy as np from tqdm import tqdm @@ -21,78 +20,77 @@ import Sofa import SofaRuntime -dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), './tools') -sys.path.append(os.path.abspath(dir)) +tools_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), './tools') +sys.path.append(os.path.abspath(tools_dir)) import RegressionSceneData import RegressionSceneParsing class RegressionProgram: - def __init__(self, inputFolder): - self.sceneSets = [] # List + def __init__(self, input_folder): + self.scene_sets = [] # List - for root, dirs, files in os.walk(inputFolder): + for root, dirs, files in os.walk(input_folder): for file in files: if file.endswith(".regression-tests"): - filePath = os.path.join(root, file) + file_path = os.path.join(root, file) - sceneList = RegressionSceneParsing.RegressionSceneList(filePath) + scene_list = RegressionSceneParsing.RegressionSceneList(file_path) - sceneList.processFile() - self.sceneSets.append(sceneList) + scene_list.process_file() + self.scene_sets.append(scene_list) - def nbrErrorInSets(self): - nbrErrors = 0 - for sceneList in self.sceneSets: - nbrErrors = nbrErrors + sceneList.getNbrErrors() - return nbrErrors - - def logErrorsInSets(self): - for sceneList in self.sceneSets: - sceneList.logScenesErrors() - - def writeSetsReferences(self, idSet = 0): - sceneList = self.sceneSets[idSet] - nbrScenes = sceneList.writeAllReferences() - return nbrScenes - - def writeAllSetsReferences(self): - nbrSets = len(self.sceneSets) - pbarSets = tqdm(total=nbrSets) - pbarSets.set_description("Write All sets") - - nbrScenes = 0 - for i in range(0, nbrSets): - nbrScenes = nbrScenes + self.writeSetsReferences(i) - pbarSets.update(1) + def nbr_error_in_sets(self): + nbr_errors = 0 + for scene_list in self.scene_sets: + nbr_errors = nbr_errors + scene_list.get_nbr_errors() + return nbr_errors - pbarSets.close() + def log_errors_in_sets(self): + for scene_list in self.scene_sets: + scene_list.log_scenes_errors() - return nbrScenes + def write_sets_references(self, id_set=0): + scene_list = self.scene_sets[id_set] + nbr_scenes = scene_list.write_all_references() + return nbr_scenes + def write_all_sets_references(self): + nbr_sets = len(self.scene_sets) + pbar_sets = tqdm(total=nbr_sets) + pbar_sets.set_description("Write All sets") - def compareSetsReferences(self, idSet = 0): - sceneList = self.sceneSets[idSet] - nbrScenes = sceneList.compareAllReferences() - return nbrScenes - - def compareAllSetsReferences(self): - nbrSets = len(self.sceneSets) - pbarSets = tqdm(total=nbrSets) - pbarSets.set_description("Compare All sets") + nbr_scenes = 0 + for i in range(0, nbr_sets): + nbr_scenes = nbr_scenes + self.write_sets_references(i) + pbar_sets.update(1) - nbrScenes = 0 - for i in range(0, nbrSets): - nbrScenes = nbrScenes + self.compareSetsReferences(i) - pbarSets.update(1) + pbar_sets.close() - pbarSets.close() + return nbr_scenes - return nbrScenes - - def replayReferences(self, idSet = 0): - sceneList = self.sceneSets[idSet] - sceneList.replayReferences(0) + def compare_sets_references(self, id_set=0): + scene_list = self.scene_sets[id_set] + nbr_scenes = scene_list.compare_all_references() + return nbr_scenes + + def compare_all_sets_references(self): + nbr_sets = len(self.scene_sets) + pbar_sets = tqdm(total=nbr_sets) + pbar_sets.set_description("Compare All sets") + + nbr_scenes = 0 + for i in range(0, nbr_sets): + nbr_scenes = nbr_scenes + self.compare_sets_references(i) + pbar_sets.update(1) + + pbar_sets.close() + + return nbr_scenes + + def replay_references(self, id_set=0): + scene_list = self.scene_sets[id_set] + scene_list.replay_references(0) @@ -118,15 +116,21 @@ def parse_args(): type=int) parser.add_argument( - "--writeRef", - dest="writeMode", - help='If true, will generate new reference files', - type=int + "--write-references", + dest="write_mode", + help='If set, will generate new reference files', + action='store_true' + ) + parser.add_argument( + "--disable-progress-bar", + dest="progress_bar_is_disabled", + help='If set, will generate new reference files', + action='store_true' ) - args = parser.parse_args() + cmdline_args = parser.parse_args() - return args + return cmdline_args @@ -141,25 +145,24 @@ def parse_args(): #SofaRuntime.disable_messages() SofaRuntime.importPlugin("SofaPython3") - nbrScenes = 0 - writeMode = bool(args.writeMode) + nbr_scenes = 0 replay = bool(args.replay) if replay is True: - regProg.replayReferences() + regProg.replay_references() sys.exit() - if writeMode is True: - nbrScenes = regProg.writeAllSetsReferences() + if args.write_mode is True: + nbr_scenes = regProg.write_all_sets_references() else: - nbrScenes = regProg.compareAllSetsReferences() + nbr_scenes = regProg.compare_all_sets_references() - print ("### Number of sets Done: " + str(len(regProg.sceneSets))) - print ("### Number of scenes Done: " + str(nbrScenes)) - if writeMode is False: - print ("### Number of scenes failed: " + str(regProg.nbrErrorInSets())) + print ("### Number of sets Done: " + str(len(regProg.scene_sets))) + print ("### Number of scenes Done: " + str(nbr_scenes)) + if args.write_mode is False: + print ("### Number of scenes failed: " + str(regProg.nbr_error_in_sets())) #np.set_printoptions(precision=8) - regProg.logErrorsInSets() + regProg.log_errors_in_sets() sys.exit() diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py index 7927a8d..4e4c738 100644 --- a/tools/RegressionSceneData.py +++ b/tools/RegressionSceneData.py @@ -8,57 +8,57 @@ import Sofa.Simulation import Sofa.Gui -debugInfo = False +debug_info = False -def isSimulated(node): - if (node.hasODESolver()): +def is_simulated(node): + if node.hasODESolver(): return True # if no Solver in current node, check parent nodes for parent in node.parents: - solverFound = isSimulated(parent) - if (solverFound): + solver_found = is_simulated(parent) + if solver_found: return True return False -def exportJson(): +def export_json(): - numpyArrayOne = np.array([[11 ,22, 33], [44, 55, 66], [77, 88, 99]]) - numpyArrayTwo = np.array([[51, 61, 91], [121 ,118, 127]]) + numpy_array_one = np.array([[11 ,22, 33], [44, 55, 66], [77, 88, 99]]) + numpy_array_two = np.array([[51, 61, 91], [121 ,118, 127]]) # Serialization - numpyData = {"arrayOne": numpyArrayOne, "arrayTwo": numpyArrayTwo} + numpy_data = {"arrayOne": numpy_array_one, "arrayTwo": numpy_array_two} print("serialize NumPy array into JSON and write into a file") with gzip.open("numpyData.json.gz", 'w') as zipfile: - for key in numpyData: - print(numpyData[key]) + for key in numpy_data: + print(numpy_data[key]) #write_file.write(json.dumps(numpyData, cls=NumpyArrayEncoder, indent=4)) #res = json.dumps(numpyData, cls=NumpyArrayEncoder, indent=4) #print(res) #json.dump(numpyData, zipfile, cls=NumpyArrayEncoder) - zipfile.write(json.dumps(numpyData, cls=NumpyArrayEncoder).encode('utf-8')) + zipfile.write(json.dumps(numpy_data, cls=NumpyArrayEncoder).encode('utf-8')) - print("Done writing serialized NumPy array into file") + print('Done writing serialized NumPy array into file') -def readJson(): +def read_json(): # Deserialization print("Started Reading JSON file") with gzip.open("numpyData.json.gz", 'r') as zipfile: #with open("numpyData.json", "r") as read_file: print("Converting JSON encoded data into Numpy array") - decodedArray = json.loads(zipfile.read().decode('utf-8')) - #decodedArray = json.load(zipfile) + decoded_array = json.loads(zipfile.read().decode('utf-8')) + #decoded_array = json.load(zipfile) - finalNumpyArrayOne = np.asarray(decodedArray["arrayOne"]) + final_numpy_array_one = np.asarray(decoded_array["arrayOne"]) print("NumPy Array One") - print(finalNumpyArrayOne) - finalNumpyArrayTwo = np.asarray(decodedArray["arrayTwo"]) + print(final_numpy_array_one) + final_numpy_array_two = np.asarray(decoded_array["arrayTwo"]) print("NumPy Array Two") - print(finalNumpyArrayTwo) + print(final_numpy_array_two) class NumpyArrayEncoder(JSONEncoder): @@ -69,8 +69,8 @@ def default(self, obj): class RegressionSceneData: - def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1000, - epsilon = 0.0001, mecaInMapping = True, dumpNumberStep = 1): + def __init__(self, file_scene_path: str = None, file_ref_path: str = None, steps = 1000, + epsilon = 0.0001, meca_in_mapping = True, dump_number_step = 1): """ /// Path to the file scene to test std::string m_fileScenePath; @@ -85,181 +85,182 @@ def __init__(self, fileScenePath: str = None, fileRefPath: str = None, steps = 1 /// Option to compare mechanicalObject dof position at each timestep bool m_dumpNumberStep; """ - self.fileScenePath = fileScenePath - self.fileRefPath = fileRefPath + self.file_scene_path = file_scene_path + self.file_ref_path = file_ref_path self.steps = int(steps) self.epsilon = float(epsilon) - self.mecaInMapping = mecaInMapping - self.dumpNumberStep = int(dumpNumberStep) - self.mecaObjs = [] - self.fileNames = [] + self.meca_in_mapping = meca_in_mapping + self.dump_number_step = int(dump_number_step) + self.meca_objs = [] + self.filenames = [] self.mins = [] self.maxs = [] - self.totalError = [] - self.errorByDof = [] - self.nbrTestedFrame = 0 - self.regressionFailed = False - - def printInfo(self): - print("Test scene: " + self.fileScenePath + " vs " + self.fileRefPath + " using: " + self.steps - + " " + self.epsilon) + self.total_error = [] + self.error_by_dof = [] + self.nbr_tested_frame = 0 + self.regression_failed = False + self.root_node = None + + def print_info(self): + print("Test scene: " + self.file_scene_path + " vs " + self.file_ref_path + " using: " + str(self.steps) + + " " + str(self.epsilon)) - def logErrors(self): - if self.regressionFailed is True: - print("### Failed: " + self.fileScenePath) - print(" ### Total Error per MechanicalObject: " + str(self.totalError)) - print(" ### Error by Dofs: " + str(self.errorByDof)) + def log_errors(self): + if self.regression_failed is True: + print("### Failed: " + self.file_scene_path) + print(" ### Total Error per MechanicalObject: " + str(self.total_error)) + print(" ### Error by Dofs: " + str(self.error_by_dof)) else: - print ("### Success: " + self.fileScenePath + " | Number of key frames compared without error: " + str(self.nbrTestedFrame)) + print ("### Success: " + self.file_scene_path + " | Number of key frames compared without error: " + str(self.nbr_tested_frame)) - def printMecaObjs(self): - print ("# Nbr Meca: " + str(len(self.mecaObjs))) + def print_meca_objs(self): + print ("# Nbr Meca: " + str(len(self.meca_objs))) counter = 0 - for mecaObj in self.mecaObjs: - filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" + for mecaObj in self.meca_objs: + filename = self.file_ref_path + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" counter = counter+1 print ("# File attached: " + filename) - def parseNode(self, node, level = 0): + def parse_node(self, node, level = 0): for child in node.children: mstate = child.getMechanicalState() - if (mstate): - if (isSimulated(child)): - self.mecaObjs.append(mstate) + if mstate: + if is_simulated(child): + self.meca_objs.append(mstate) - self.parseNode(child, level+1) + self.parse_node(child, level + 1) - def addCompareState(self): + def add_compare_state(self): counter = 0 - for mecaObj in self.mecaObjs: - _filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" + for meca_obj in self.meca_objs: + _filename = self.file_ref_path + ".reference_" + str(counter) + "_" + meca_obj.name.value + "_mstate" + ".txt.gz" - mecaObj.getContext().addObject('CompareState', filename=_filename) + meca_obj.getContext().addObject('CompareState', filename=_filename) counter = counter+1 - def addWriteState(self): + def add_write_state(self): counter = 0 - for mecaObj in self.mecaObjs: - _filename = self.fileRefPath + ".reference_" + str(counter) + "_" + mecaObj.name.value + "_mstate" + ".txt.gz" + for meca_obj in self.meca_objs: + _filename = self.file_ref_path + ".reference_" + str(counter) + "_" + meca_obj.name.value + "_mstate" + ".txt.gz" - mecaObj.getContext().addObject('WriteState', filename=_filename) + meca_obj.getContext().addObject('WriteState', filename=_filename) counter = counter+1 - def loadScene(self): - self.rootNode = Sofa.Simulation.load(self.fileScenePath) - Sofa.Simulation.init(self.rootNode) + def load_scene(self): + self.root_node = Sofa.Simulation.load(self.file_scene_path) + Sofa.Simulation.init(self.root_node) # prepare ref files per mecaObjs: - self.parseNode(self.rootNode, 0) + self.parse_node(self.root_node, 0) counter = 0 - for mecaObj in self.mecaObjs: - _filename = self.fileRefPath + ".reference_mstate_" + str(counter) + "_" + mecaObj.name.value + ".json.gz" - self.fileNames.append(_filename) + for mecaObj in self.meca_objs: + _filename = self.file_ref_path + ".reference_mstate_" + str(counter) + "_" + mecaObj.name.value + ".json.gz" + self.filenames.append(_filename) counter = counter+1 - def writeReferences(self): - pbarSimu = tqdm(total=self.steps) - pbarSimu.set_description("Simulate: " + self.fileScenePath) + def write_references(self): + pbar_simu = tqdm(total=self.steps) + pbar_simu.set_description("Simulate: " + self.file_scene_path) - nbrMeca = len(self.mecaObjs) - numpyData = [] # List - for mecaId in range(0, nbrMeca): - mecaDofs = {} - numpyData.append(mecaDofs) + nbr_meca = len(self.meca_objs) + numpy_data = [] # List + for meca_id in range(0, nbr_meca): + meca_dofs = {} + numpy_data.append(meca_dofs) - counterStep = 0 - moduloStep = (self.steps) / self.dumpNumberStep + counter_step = 0 + modulo_step = self.steps / self.dump_number_step for step in range(0, self.steps + 1): # export rest position, final position + modulo steps: - if (step == 0 or counterStep >= moduloStep or step == self.steps): - #print("step: " + str(step) + " | counterStep: " + str(counterStep) + " | moduloStep: " + str(moduloStep) + " | dt: " + str(self.rootNode.dt.value*(step))) - for mecaId in range(0, nbrMeca): - numpyData[mecaId][self.rootNode.dt.value*(step)] = np.copy(self.mecaObjs[mecaId].position.value) - counterStep = 0 + if step == 0 or counter_step >= modulo_step or step == self.steps: + #print("step: " + str(step) + " | counter_step: " + str(counter_step) + " | modulo_step: " + str(modulo_step) + " | dt: " + str(self.rootNode.dt.value*(step))) + for meca_id in range(0, nbr_meca): + numpy_data[meca_id][self.root_node.dt.value * step] = np.copy(self.meca_objs[meca_id].position.value) + counter_step = 0 - Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) - counterStep = counterStep + 1 + Sofa.Simulation.animate(self.root_node, self.root_node.dt.value) + counter_step = counter_step + 1 - pbarSimu.update(1) - pbarSimu.close() + pbar_simu.update(1) + pbar_simu.close() - for mecaId in range(0, nbrMeca): - #for key in numpyData[mecaId]: - # print("key: %s , value: %s" % (key, numpyData[mecaId][key][820])) - with gzip.open(self.fileNames[mecaId], "w") as write_file: - write_file.write(json.dumps(numpyData[mecaId], cls=NumpyArrayEncoder).encode('utf-8')) + for meca_id in range(0, nbr_meca): + #for key in numpy_data[meca_id]: + # print("key: %s , value: %s" % (key, numpy_data[meca_id][key][820])) + with gzip.open(self.filenames[meca_id], "w") as write_file: + write_file.write(json.dumps(numpy_data[meca_id], cls=NumpyArrayEncoder).encode('utf-8')) - Sofa.Simulation.unload(self.rootNode) + Sofa.Simulation.unload(self.root_node) - def compareReferences(self): - pbarSimu = tqdm(total=float(self.steps)) - pbarSimu.set_description("compareReferences: " + self.fileScenePath) + def compare_references(self): + pbar_simu = tqdm(total=float(self.steps), disable=True) + pbar_simu.set_description("compareReferences: " + self.file_scene_path) - nbrMeca = len(self.mecaObjs) - numpyData = [] # List + nbr_meca = len(self.meca_objs) + numpy_data = [] # List keyframes = [] - self.totalError = [] - self.errorByDof = [] + self.total_error = [] + self.error_by_dof = [] - for mecaId in range(0, nbrMeca): - with gzip.open(self.fileNames[mecaId], 'r') as zipfile: - decodedArray = json.loads(zipfile.read().decode('utf-8')) - numpyData.append(decodedArray) + for meca_id in range(0, nbr_meca): + with gzip.open(self.filenames[meca_id], 'r') as zipfile: + decoded_array = json.loads(zipfile.read().decode('utf-8')) + numpy_data.append(decoded_array) - if mecaId == 0: - for key in decodedArray: + if meca_id == 0: + for key in decoded_array: keyframes.append(float(key)) - self.totalError.append(0.0) - self.errorByDof.append(0.0) + self.total_error.append(0.0) + self.error_by_dof.append(0.0) - frameStep = 0 - nbrFrames = len(keyframes) - self.nbrTestedFrame = 0 + frame_step = 0 + nbr_frames = len(keyframes) + self.nbr_tested_frame = 0 for step in range(0, self.steps + 1): - simuTime = self.rootNode.dt.value*(step) + simu_time = self.root_node.dt.value * step - if (simuTime == keyframes[frameStep]): - for mecaId in range(0, nbrMeca): - mecaDofs = np.copy(self.mecaObjs[mecaId].position.value) - dataRef = np.asarray(numpyData[mecaId][str(keyframes[frameStep])]) - mecaDofs + if simu_time == keyframes[frame_step]: + for meca_id in range(0, nbr_meca): + meca_dofs = np.copy(self.meca_objs[meca_id].position.value) + data_ref = np.asarray(numpy_data[meca_id][str(keyframes[frame_step])]) - meca_dofs # Compute total distance between the 2 sets - fullDist = np.linalg.norm(dataRef) - errorByDof = fullDist / float(dataRef.size) + full_dist = np.linalg.norm(data_ref) + error_by_dof = full_dist / float(data_ref.size) - if (debugInfo is True): - print (str(step) + "| " + self.mecaObjs[mecaId].name.value + " | fullDist: " + str(fullDist) + " | errorByDof: " + str(errorByDof) + " | nbrDofs: " + str(dataRef.size)) + if debug_info: + print (str(step) + "| " + self.meca_objs[meca_id].name.value + " | full_dist: " + str(full_dist) + " | error_by_dof: " + str(error_by_dof) + " | nbrDofs: " + str(data_ref.size)) - self.totalError[mecaId] = self.totalError[mecaId] + fullDist - self.errorByDof[mecaId] = self.errorByDof[mecaId] + errorByDof + self.total_error[meca_id] = self.total_error[meca_id] + full_dist + self.error_by_dof[meca_id] = self.error_by_dof[meca_id] + error_by_dof - frameStep = frameStep + 1 - self.nbrTestedFrame = self.nbrTestedFrame + 1 + frame_step = frame_step + 1 + self.nbr_tested_frame = self.nbr_tested_frame + 1 - # security exit if simulation steps exceed nbrFrames - if (frameStep == nbrFrames): + # security exit if simulation steps exceed nbr_frames + if frame_step == nbr_frames: break - Sofa.Simulation.animate(self.rootNode, self.rootNode.dt.value) + Sofa.Simulation.animate(self.root_node, self.root_node.dt.value) - pbarSimu.update(1) - pbarSimu.close() + pbar_simu.update(1) + pbar_simu.close() - for mecaId in range(0, nbrMeca): - if (self.totalError[mecaId] > self.epsilon): - self.regressionFailed = True + for meca_id in range(0, nbr_meca): + if self.total_error[meca_id] > self.epsilon: + self.regression_failed = True return False return True @@ -267,9 +268,9 @@ def compareReferences(self): def replayReferences(self): Sofa.Gui.GUIManager.Init("myscene", "qglviewer") - Sofa.Gui.GUIManager.createGUI(self.rootNode, __file__) + Sofa.Gui.GUIManager.createGUI(self.root_node, __file__) Sofa.Gui.GUIManager.SetDimension(1080, 1080) - Sofa.Gui.GUIManager.MainLoop(self.rootNode) + Sofa.Gui.GUIManager.MainLoop(self.root_node) Sofa.Gui.GUIManager.closeGUI() diff --git a/tools/RegressionSceneParsing.py b/tools/RegressionSceneParsing.py index 56beaa2..29d78da 100644 --- a/tools/RegressionSceneParsing.py +++ b/tools/RegressionSceneParsing.py @@ -1,4 +1,4 @@ -import sys, os +import os import RegressionSceneData from tqdm import tqdm @@ -6,103 +6,104 @@ ## This class is responsible for loading a file.regression-tests to gather the list of scene to test with all arguments ## It will provide the API to launch the tests or write refs on all scenes contained in this file class RegressionSceneList: - def __init__(self, filePath): + def __init__(self, file_path): """ /// Path to the file.regression-tests containing the list of scene to tests with all arguments std::string filePath; """ - self.filePath = filePath - self.fileDir = os.path.dirname(filePath) + self.file_path = file_path + self.file_dir = os.path.dirname(file_path) self.scenes = [] # List - self.nbrErrors = 0 + self.nbr_errors = 0 + self.ref_dir_path = None - def getNbrScenes(self): + def get_nbr_scenes(self): return len(self.scenes) - def getNbrErrors(self): - return self.nbrErrors + def get_nbr_errors(self): + return self.nbr_errors - def logScenesErrors(self): + def log_scenes_errors(self): for scene in self.scenes: - scene.logErrors() + scene.log_errors() - def processFile(self): - with open(self.filePath, 'r') as thefile: - data = thefile.readlines() - thefile.close() + def process_file(self): + with open(self.file_path, 'r') as the_file: + data = the_file.readlines() + the_file.close() count = 0 for idx, line in enumerate(data): - if (line[0] == "#"): + if line[0] == "#": continue values = line.split() - if (len(values) == 0): + if len(values) == 0: continue - if (count == 0): - self.refDirPath = os.path.join(self.fileDir, values[0]) - self.refDirPath = os.path.abspath(self.refDirPath) + if count == 0: + self.ref_dir_path = os.path.join(self.file_dir, values[0]) + self.ref_dir_path = os.path.abspath(self.ref_dir_path) count = count + 1 continue - if (len(values) != 5): + if len(values) != 5: print ("line read has not 5 arguments: " + str(len(values)) + " -> " + line) continue - fullFilePath = os.path.join(self.fileDir, values[0]) - fullRefFilePath = os.path.join(self.refDirPath, values[0]) + full_file_path = os.path.join(self.file_dir, values[0]) + full_ref_file_path = os.path.join(self.ref_dir_path, values[0]) - if (len(values) == 5): - sceneData = RegressionSceneData.RegressionSceneData(fullFilePath, fullRefFilePath, values[1], values[2], values[3], values[4]) + if len(values) == 5: + scene_data = RegressionSceneData.RegressionSceneData(full_file_path, full_ref_file_path, values[1], values[2], values[3], values[4]) - #sceneData.printInfo() - self.scenes.append(sceneData) + #scene_data.printInfo() + self.scenes.append(scene_data) - def writeReferences(self, idScene, printLog = False): - self.scenes[idScene].loadScene() - if (printLog is True): - self.scenes[idScene].printMecaObjs() + def write_references(self, id_scene, print_log = False): + self.scenes[id_scene].load_scene() + if print_log is True: + self.scenes[id_scene].print_meca_objs() - self.scenes[idScene].writeReferences() + self.scenes[id_scene].write_references() - def writeAllReferences(self): - nbrScenes = len(self.scenes) - pbarScenes = tqdm(total=nbrScenes) - pbarScenes.set_description("Write all scenes from: " + self.filePath) + def write_all_references(self): + nbr_scenes = len(self.scenes) + pbar_scenes = tqdm(total=nbr_scenes) + pbar_scenes.set_description("Write all scenes from: " + self.file_path) - for i in range(0, nbrScenes): - self.writeReferences(i) - pbarScenes.update(1) - pbarScenes.close() + for i in range(0, nbr_scenes): + self.write_references(i) + pbar_scenes.update(1) + pbar_scenes.close() - return nbrScenes + return nbr_scenes - def compareReferences(self, idScene): - self.scenes[idScene].loadScene() - result = self.scenes[idScene].compareReferences() - if (result == False): - self.nbrErrors = self.nbrErrors + 1 + def compare_references(self, id_scene): + self.scenes[id_scene].load_scene() + result = self.scenes[id_scene].compare_references() + if not result: + self.nbr_errors = self.nbr_errors + 1 - def compareAllReferences(self): - nbrScenes = len(self.scenes) - pbarScenes = tqdm(total=nbrScenes) - pbarScenes.set_description("Compare all scenes from: " + self.filePath) + def compare_all_references(self): + nbr_scenes = len(self.scenes) + pbar_scenes = tqdm(total=nbr_scenes) + pbar_scenes.set_description("Compare all scenes from: " + self.file_path) - for i in range(0, nbrScenes): - self.compareReferences(i) - pbarScenes.update(1) - pbarScenes.close() + for i in range(0, nbr_scenes): + self.compare_references(i) + pbar_scenes.update(1) + pbar_scenes.close() - return nbrScenes + return nbr_scenes - def replayReferences(self, idScene): - self.scenes[idScene].loadScene() - self.scenes[idScene].replayReferences() + def replay_references(self, id_scene): + self.scenes[id_scene].load_scene() + self.scenes[id_scene].replay_references() From b09dc4b493a3c2d1559d88d9d2459c6f16835dde Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Mon, 23 Dec 2024 10:47:41 +0900 Subject: [PATCH 20/28] add option to disable progress bars --- new_regression.py | 15 ++++++++------- tools/RegressionSceneData.py | 7 ++++--- tools/RegressionSceneParsing.py | 11 +++++++---- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/new_regression.py b/new_regression.py index 5826cfc..b0ca4fc 100644 --- a/new_regression.py +++ b/new_regression.py @@ -27,15 +27,16 @@ class RegressionProgram: - def __init__(self, input_folder): + def __init__(self, input_folder, disable_progress_bar = False): self.scene_sets = [] # List + self.disable_progress_bar = disable_progress_bar for root, dirs, files in os.walk(input_folder): for file in files: if file.endswith(".regression-tests"): file_path = os.path.join(root, file) - scene_list = RegressionSceneParsing.RegressionSceneList(file_path) + scene_list = RegressionSceneParsing.RegressionSceneList(file_path, self.disable_progress_bar) scene_list.process_file() self.scene_sets.append(scene_list) @@ -52,12 +53,12 @@ def log_errors_in_sets(self): def write_sets_references(self, id_set=0): scene_list = self.scene_sets[id_set] - nbr_scenes = scene_list.write_all_references() + nbr_scenes = scene_list.write_all_references(self.disable_progress_bar) return nbr_scenes def write_all_sets_references(self): nbr_sets = len(self.scene_sets) - pbar_sets = tqdm(total=nbr_sets) + pbar_sets = tqdm(total=nbr_sets, disable=self.disable_progress_bar) pbar_sets.set_description("Write All sets") nbr_scenes = 0 @@ -76,7 +77,7 @@ def compare_sets_references(self, id_set=0): def compare_all_sets_references(self): nbr_sets = len(self.scene_sets) - pbar_sets = tqdm(total=nbr_sets) + pbar_sets = tqdm(total=nbr_sets, disable=self.disable_progress_bar) pbar_sets.set_description("Compare All sets") nbr_scenes = 0 @@ -124,7 +125,7 @@ def parse_args(): parser.add_argument( "--disable-progress-bar", dest="progress_bar_is_disabled", - help='If set, will generate new reference files', + help='If set, will disable progress bars', action='store_true' ) @@ -139,7 +140,7 @@ def parse_args(): args = parse_args() # 2- Process file if args.input is not None: - regProg = RegressionProgram(args.input) + regProg = RegressionProgram(args.input, args.progress_bar_is_disabled) else: exit("Error: Argument is required ! Quitting.") #SofaRuntime.disable_messages() diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py index 4e4c738..bc56531 100644 --- a/tools/RegressionSceneData.py +++ b/tools/RegressionSceneData.py @@ -70,7 +70,7 @@ def default(self, obj): class RegressionSceneData: def __init__(self, file_scene_path: str = None, file_ref_path: str = None, steps = 1000, - epsilon = 0.0001, meca_in_mapping = True, dump_number_step = 1): + epsilon = 0.0001, meca_in_mapping = True, dump_number_step = 1, disable_progress_bar = False): """ /// Path to the file scene to test std::string m_fileScenePath; @@ -100,6 +100,7 @@ def __init__(self, file_scene_path: str = None, file_ref_path: str = None, steps self.nbr_tested_frame = 0 self.regression_failed = False self.root_node = None + self.disable_progress_bar = disable_progress_bar def print_info(self): print("Test scene: " + self.file_scene_path + " vs " + self.file_ref_path + " using: " + str(self.steps) @@ -166,7 +167,7 @@ def load_scene(self): def write_references(self): - pbar_simu = tqdm(total=self.steps) + pbar_simu = tqdm(total=self.steps, disable=self.disable_progress_bar) pbar_simu.set_description("Simulate: " + self.file_scene_path) nbr_meca = len(self.meca_objs) @@ -203,7 +204,7 @@ def write_references(self): def compare_references(self): - pbar_simu = tqdm(total=float(self.steps), disable=True) + pbar_simu = tqdm(total=float(self.steps), disable=self.disable_progress_bar) pbar_simu.set_description("compareReferences: " + self.file_scene_path) nbr_meca = len(self.meca_objs) diff --git a/tools/RegressionSceneParsing.py b/tools/RegressionSceneParsing.py index 29d78da..82c73fb 100644 --- a/tools/RegressionSceneParsing.py +++ b/tools/RegressionSceneParsing.py @@ -6,7 +6,7 @@ ## This class is responsible for loading a file.regression-tests to gather the list of scene to test with all arguments ## It will provide the API to launch the tests or write refs on all scenes contained in this file class RegressionSceneList: - def __init__(self, file_path): + def __init__(self, file_path, disable_progress_bar = False): """ /// Path to the file.regression-tests containing the list of scene to tests with all arguments std::string filePath; @@ -16,6 +16,7 @@ def __init__(self, file_path): self.scenes = [] # List self.nbr_errors = 0 self.ref_dir_path = None + self.disable_progress_bar = disable_progress_bar def get_nbr_scenes(self): @@ -57,7 +58,9 @@ def process_file(self): full_ref_file_path = os.path.join(self.ref_dir_path, values[0]) if len(values) == 5: - scene_data = RegressionSceneData.RegressionSceneData(full_file_path, full_ref_file_path, values[1], values[2], values[3], values[4]) + scene_data = RegressionSceneData.RegressionSceneData(full_file_path, full_ref_file_path, + values[1], values[2], values[3], values[4], + self.disable_progress_bar) #scene_data.printInfo() self.scenes.append(scene_data) @@ -72,7 +75,7 @@ def write_references(self, id_scene, print_log = False): def write_all_references(self): nbr_scenes = len(self.scenes) - pbar_scenes = tqdm(total=nbr_scenes) + pbar_scenes = tqdm(total=nbr_scenes, disable=self.disable_progress_bar) pbar_scenes.set_description("Write all scenes from: " + self.file_path) for i in range(0, nbr_scenes): @@ -91,7 +94,7 @@ def compare_references(self, id_scene): def compare_all_references(self): nbr_scenes = len(self.scenes) - pbar_scenes = tqdm(total=nbr_scenes) + pbar_scenes = tqdm(total=nbr_scenes, disable=self.disable_progress_bar) pbar_scenes.set_description("Compare all scenes from: " + self.file_path) for i in range(0, nbr_scenes): From e2811f155a262f657f71a61b3d2a374c637bfd4e Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Mon, 23 Dec 2024 12:38:25 +0900 Subject: [PATCH 21/28] fix crash --- new_regression.py | 31 ++++++++++++------------------- tools/RegressionSceneData.py | 23 +++++++++++++---------- tools/RegressionSceneParsing.py | 12 ++++++++---- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/new_regression.py b/new_regression.py index b0ca4fc..450aece 100644 --- a/new_regression.py +++ b/new_regression.py @@ -17,13 +17,8 @@ sofapython3_path = os.environ["SOFA_ROOT"] + "/lib/python3/site-packages" sys.path.append(sofapython3_path) -import Sofa -import SofaRuntime - -tools_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), './tools') -sys.path.append(os.path.abspath(tools_dir)) -import RegressionSceneData -import RegressionSceneParsing +import SofaRuntime # importing SofaRuntime will add the py3 loader to the scene loaders +import tools.RegressionSceneParsing as RegressionSceneParsing class RegressionProgram: @@ -140,31 +135,29 @@ def parse_args(): args = parse_args() # 2- Process file if args.input is not None: - regProg = RegressionProgram(args.input, args.progress_bar_is_disabled) + reg_prog = RegressionProgram(args.input, args.progress_bar_is_disabled) else: exit("Error: Argument is required ! Quitting.") - #SofaRuntime.disable_messages() - SofaRuntime.importPlugin("SofaPython3") nbr_scenes = 0 replay = bool(args.replay) - if replay is True: - regProg.replay_references() + if replay: + reg_prog.replay_references() sys.exit() - if args.write_mode is True: - nbr_scenes = regProg.write_all_sets_references() + if args.write_mode: + nbr_scenes = reg_prog.write_all_sets_references() else: - nbr_scenes = regProg.compare_all_sets_references() + nbr_scenes = reg_prog.compare_all_sets_references() - print ("### Number of sets Done: " + str(len(regProg.scene_sets))) + print ("### Number of sets Done: " + str(len(reg_prog.scene_sets))) print ("### Number of scenes Done: " + str(nbr_scenes)) if args.write_mode is False: - print ("### Number of scenes failed: " + str(regProg.nbr_error_in_sets())) + print ("### Number of scenes failed: " + str(reg_prog.nbr_error_in_sets())) #np.set_printoptions(precision=8) - regProg.log_errors_in_sets() - + reg_prog.log_errors_in_sets() + sys.exit() diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py index bc56531..4c82746 100644 --- a/tools/RegressionSceneData.py +++ b/tools/RegressionSceneData.py @@ -5,7 +5,6 @@ import gzip import Sofa -import Sofa.Simulation import Sofa.Gui debug_info = False @@ -154,15 +153,19 @@ def add_write_state(self): def load_scene(self): self.root_node = Sofa.Simulation.load(self.file_scene_path) - Sofa.Simulation.init(self.root_node) - - # prepare ref files per mecaObjs: - self.parse_node(self.root_node, 0) - counter = 0 - for mecaObj in self.meca_objs: - _filename = self.file_ref_path + ".reference_mstate_" + str(counter) + "_" + mecaObj.name.value + ".json.gz" - self.filenames.append(_filename) - counter = counter+1 + if not self.root_node: # error while loading + print(f'Error while trying to load {self.file_scene_path}') + raise RuntimeError + else: + Sofa.Simulation.init(self.root_node) + + # prepare ref files per mecaObjs: + self.parse_node(self.root_node, 0) + counter = 0 + for mecaObj in self.meca_objs: + _filename = self.file_ref_path + ".reference_mstate_" + str(counter) + "_" + mecaObj.name.value + ".json.gz" + self.filenames.append(_filename) + counter = counter+1 diff --git a/tools/RegressionSceneParsing.py b/tools/RegressionSceneParsing.py index 82c73fb..06019c9 100644 --- a/tools/RegressionSceneParsing.py +++ b/tools/RegressionSceneParsing.py @@ -1,5 +1,5 @@ import os -import RegressionSceneData +import tools.RegressionSceneData as RegressionSceneData from tqdm import tqdm @@ -87,10 +87,14 @@ def write_all_references(self): def compare_references(self, id_scene): - self.scenes[id_scene].load_scene() - result = self.scenes[id_scene].compare_references() - if not result: + try: + self.scenes[id_scene].load_scene() + except Exception as e: self.nbr_errors = self.nbr_errors + 1 + else: + result = self.scenes[id_scene].compare_references() + if not result: + self.nbr_errors = self.nbr_errors + 1 def compare_all_references(self): nbr_scenes = len(self.scenes) From af52c406c2c2ca64442762b19633996719d35e04 Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Mon, 23 Dec 2024 12:55:19 +0900 Subject: [PATCH 22/28] add some safeguards --- tools/RegressionSceneData.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py index 4c82746..050e5ed 100644 --- a/tools/RegressionSceneData.py +++ b/tools/RegressionSceneData.py @@ -215,18 +215,22 @@ def compare_references(self): keyframes = [] self.total_error = [] self.error_by_dof = [] - - for meca_id in range(0, nbr_meca): - with gzip.open(self.filenames[meca_id], 'r') as zipfile: - decoded_array = json.loads(zipfile.read().decode('utf-8')) - numpy_data.append(decoded_array) - if meca_id == 0: - for key in decoded_array: - keyframes.append(float(key)) - - self.total_error.append(0.0) - self.error_by_dof.append(0.0) + try: + for meca_id in range(0, nbr_meca): + with gzip.open(self.filenames[meca_id], 'r') as zipfile: + decoded_array = json.loads(zipfile.read().decode('utf-8')) + numpy_data.append(decoded_array) + + if meca_id == 0: + for key in decoded_array: + keyframes.append(float(key)) + + self.total_error.append(0.0) + self.error_by_dof.append(0.0) + except FileNotFoundError as e: + print(f'Error while reading references: {str(e)}') + return False frame_step = 0 From 548e14df0179df74fee270c2951883641d96522a Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Mon, 23 Dec 2024 14:24:51 +0900 Subject: [PATCH 23/28] fix writting references (check dir) --- new_regression.py | 2 +- tools/RegressionSceneData.py | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/new_regression.py b/new_regression.py index 450aece..5ba1a6f 100644 --- a/new_regression.py +++ b/new_regression.py @@ -48,7 +48,7 @@ def log_errors_in_sets(self): def write_sets_references(self, id_set=0): scene_list = self.scene_sets[id_set] - nbr_scenes = scene_list.write_all_references(self.disable_progress_bar) + nbr_scenes = scene_list.write_all_references() return nbr_scenes def write_all_sets_references(self): diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py index 050e5ed..6ad79a4 100644 --- a/tools/RegressionSceneData.py +++ b/tools/RegressionSceneData.py @@ -3,6 +3,7 @@ from json import JSONEncoder import numpy as np import gzip +import pathlib import Sofa import Sofa.Gui @@ -198,9 +199,13 @@ def write_references(self): pbar_simu.close() for meca_id in range(0, nbr_meca): + # make sure the parent directory of the references exists + output_file = pathlib.Path(self.filenames[meca_id]) + output_file.parent.mkdir(exist_ok=True, parents=True) + #for key in numpy_data[meca_id]: # print("key: %s , value: %s" % (key, numpy_data[meca_id][key][820])) - with gzip.open(self.filenames[meca_id], "w") as write_file: + with gzip.open(self.filenames[meca_id], 'wb') as write_file: write_file.write(json.dumps(numpy_data[meca_id], cls=NumpyArrayEncoder).encode('utf-8')) Sofa.Simulation.unload(self.root_node) @@ -208,7 +213,7 @@ def write_references(self): def compare_references(self): pbar_simu = tqdm(total=float(self.steps), disable=self.disable_progress_bar) - pbar_simu.set_description("compareReferences: " + self.file_scene_path) + pbar_simu.set_description("compare_references: " + self.file_scene_path) nbr_meca = len(self.meca_objs) numpy_data = [] # List From c47968466b9846dd1db441c84c4ae78fa9d682a7 Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Mon, 23 Dec 2024 14:46:42 +0900 Subject: [PATCH 24/28] fix printing list of np.float --- new_regression.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/new_regression.py b/new_regression.py index 5ba1a6f..791c127 100644 --- a/new_regression.py +++ b/new_regression.py @@ -1,6 +1,7 @@ import os import argparse import sys +import numpy as np from tqdm import tqdm @@ -151,6 +152,8 @@ def parse_args(): else: nbr_scenes = reg_prog.compare_all_sets_references() + np.set_printoptions(legacy='1.25') # revert printing floating-point type in numpy (concretely remove np.array when displaying a list of np.float) + print ("### Number of sets Done: " + str(len(reg_prog.scene_sets))) print ("### Number of scenes Done: " + str(nbr_scenes)) if args.write_mode is False: From 0bf507be56e43f1c9a140610a1ebbe7a760f1c64 Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Tue, 24 Dec 2024 14:26:53 +0900 Subject: [PATCH 25/28] set error code when exiting --- new_regression.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/new_regression.py b/new_regression.py index 791c127..dda6fae 100644 --- a/new_regression.py +++ b/new_regression.py @@ -158,9 +158,10 @@ def parse_args(): print ("### Number of scenes Done: " + str(nbr_scenes)) if args.write_mode is False: print ("### Number of scenes failed: " + str(reg_prog.nbr_error_in_sets())) - #np.set_printoptions(precision=8) reg_prog.log_errors_in_sets() + if reg_prog.nbr_error_in_sets() > 0: + sys.exit(1) # exit with error(s) - sys.exit() + sys.exit(0) # exit without error From d40d86a2e6220b1c634c70a5aa169b17f7e8266d Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Tue, 24 Dec 2024 15:18:22 +0900 Subject: [PATCH 26/28] add verbose option --- new_regression.py | 14 +++++++++++--- tools/RegressionSceneParsing.py | 10 +++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/new_regression.py b/new_regression.py index dda6fae..c9d9aeb 100644 --- a/new_regression.py +++ b/new_regression.py @@ -18,21 +18,23 @@ sofapython3_path = os.environ["SOFA_ROOT"] + "/lib/python3/site-packages" sys.path.append(sofapython3_path) +import Sofa import SofaRuntime # importing SofaRuntime will add the py3 loader to the scene loaders import tools.RegressionSceneParsing as RegressionSceneParsing class RegressionProgram: - def __init__(self, input_folder, disable_progress_bar = False): + def __init__(self, input_folder, disable_progress_bar = False, verbose = False): self.scene_sets = [] # List self.disable_progress_bar = disable_progress_bar + self.verbose = verbose for root, dirs, files in os.walk(input_folder): for file in files: if file.endswith(".regression-tests"): file_path = os.path.join(root, file) - scene_list = RegressionSceneParsing.RegressionSceneList(file_path, self.disable_progress_bar) + scene_list = RegressionSceneParsing.RegressionSceneList(file_path, self.disable_progress_bar, verbose) scene_list.process_file() self.scene_sets.append(scene_list) @@ -124,6 +126,12 @@ def parse_args(): help='If set, will disable progress bars', action='store_true' ) + parser.add_argument( + "--verbose", + dest="verbose", + help='If set, will display more information', + action='store_true' + ) cmdline_args = parser.parse_args() @@ -136,7 +144,7 @@ def parse_args(): args = parse_args() # 2- Process file if args.input is not None: - reg_prog = RegressionProgram(args.input, args.progress_bar_is_disabled) + reg_prog = RegressionProgram(args.input, args.progress_bar_is_disabled, args.verbose) else: exit("Error: Argument is required ! Quitting.") diff --git a/tools/RegressionSceneParsing.py b/tools/RegressionSceneParsing.py index 06019c9..f37dccc 100644 --- a/tools/RegressionSceneParsing.py +++ b/tools/RegressionSceneParsing.py @@ -6,7 +6,7 @@ ## This class is responsible for loading a file.regression-tests to gather the list of scene to test with all arguments ## It will provide the API to launch the tests or write refs on all scenes contained in this file class RegressionSceneList: - def __init__(self, file_path, disable_progress_bar = False): + def __init__(self, file_path, disable_progress_bar = False, verbose = False): """ /// Path to the file.regression-tests containing the list of scene to tests with all arguments std::string filePath; @@ -17,6 +17,7 @@ def __init__(self, file_path, disable_progress_bar = False): self.nbr_errors = 0 self.ref_dir_path = None self.disable_progress_bar = disable_progress_bar + self.verbose = verbose def get_nbr_scenes(self): @@ -67,6 +68,9 @@ def process_file(self): def write_references(self, id_scene, print_log = False): + if self.verbose: + print(f'Writing reference files for {self.scenes[id_scene].file_path}.') + self.scenes[id_scene].load_scene() if print_log is True: self.scenes[id_scene].print_meca_objs() @@ -87,10 +91,14 @@ def write_all_references(self): def compare_references(self, id_scene): + if self.verbose: + self.scenes[id_scene].print_info() + try: self.scenes[id_scene].load_scene() except Exception as e: self.nbr_errors = self.nbr_errors + 1 + print(f'Error while trying to load: {str(e)}') else: result = self.scenes[id_scene].compare_references() if not result: From 5d2e4b8fba891e40e4b1114807015f5957db37e2 Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Thu, 26 Dec 2024 16:24:37 +0900 Subject: [PATCH 27/28] remove hardcoded paths --- new_regression.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/new_regression.py b/new_regression.py index c9d9aeb..001baae 100644 --- a/new_regression.py +++ b/new_regression.py @@ -6,14 +6,8 @@ from tqdm import tqdm if "SOFA_ROOT" not in os.environ: - sofa_real_root = "/Users/fred/Work/sofa" - sofa_root = sofa_real_root + "/build/current-ninja" - sofapython3_path = sofa_root + "/lib/python3/site-packages" - sofa_build_configuration = "Release" - - os.environ["SOFA_ROOT"] = sofa_root - os.environ["SOFA_BUILD_CONFIGURATION"] = sofa_build_configuration - sys.path.append(sofapython3_path) + print('SOFA_ROOT environment variable has not been detected, quitting.') + exit(1) else: sofapython3_path = os.environ["SOFA_ROOT"] + "/lib/python3/site-packages" sys.path.append(sofapython3_path) From 0235716f18ed2787381d02101685a9b2e02e1c3a Mon Sep 17 00:00:00 2001 From: epernod Date: Fri, 8 Aug 2025 19:48:49 +0200 Subject: [PATCH 28/28] remove unnecessary code --- tools/RegressionSceneData.py | 41 ------------------------------------ 1 file changed, 41 deletions(-) diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py index 6ad79a4..ad797c5 100644 --- a/tools/RegressionSceneData.py +++ b/tools/RegressionSceneData.py @@ -23,44 +23,6 @@ def is_simulated(node): return False -def export_json(): - - numpy_array_one = np.array([[11 ,22, 33], [44, 55, 66], [77, 88, 99]]) - numpy_array_two = np.array([[51, 61, 91], [121 ,118, 127]]) - - # Serialization - numpy_data = {"arrayOne": numpy_array_one, "arrayTwo": numpy_array_two} - print("serialize NumPy array into JSON and write into a file") - with gzip.open("numpyData.json.gz", 'w') as zipfile: - for key in numpy_data: - print(numpy_data[key]) - - #write_file.write(json.dumps(numpyData, cls=NumpyArrayEncoder, indent=4)) - #res = json.dumps(numpyData, cls=NumpyArrayEncoder, indent=4) - #print(res) - #json.dump(numpyData, zipfile, cls=NumpyArrayEncoder) - zipfile.write(json.dumps(numpy_data, cls=NumpyArrayEncoder).encode('utf-8')) - - print('Done writing serialized NumPy array into file') - -def read_json(): - # Deserialization - print("Started Reading JSON file") - with gzip.open("numpyData.json.gz", 'r') as zipfile: - - #with open("numpyData.json", "r") as read_file: - print("Converting JSON encoded data into Numpy array") - decoded_array = json.loads(zipfile.read().decode('utf-8')) - #decoded_array = json.load(zipfile) - - final_numpy_array_one = np.asarray(decoded_array["arrayOne"]) - print("NumPy Array One") - print(final_numpy_array_one) - final_numpy_array_two = np.asarray(decoded_array["arrayTwo"]) - print("NumPy Array Two") - print(final_numpy_array_two) - - class NumpyArrayEncoder(JSONEncoder): def default(self, obj): if isinstance(obj, np.ndarray): @@ -187,7 +149,6 @@ def write_references(self): for step in range(0, self.steps + 1): # export rest position, final position + modulo steps: if step == 0 or counter_step >= modulo_step or step == self.steps: - #print("step: " + str(step) + " | counter_step: " + str(counter_step) + " | modulo_step: " + str(modulo_step) + " | dt: " + str(self.rootNode.dt.value*(step))) for meca_id in range(0, nbr_meca): numpy_data[meca_id][self.root_node.dt.value * step] = np.copy(self.meca_objs[meca_id].position.value) counter_step = 0 @@ -203,8 +164,6 @@ def write_references(self): output_file = pathlib.Path(self.filenames[meca_id]) output_file.parent.mkdir(exist_ok=True, parents=True) - #for key in numpy_data[meca_id]: - # print("key: %s , value: %s" % (key, numpy_data[meca_id][key][820])) with gzip.open(self.filenames[meca_id], 'wb') as write_file: write_file.write(json.dumps(numpy_data[meca_id], cls=NumpyArrayEncoder).encode('utf-8'))