From 7ced7c9eb93bb23e97246ae55b9cdbf0c15698c6 Mon Sep 17 00:00:00 2001 From: epernod Date: Wed, 14 Jan 2026 23:18:54 +0100 Subject: [PATCH 1/5] Add verbose mode in Data --- tools/RegressionSceneData.py | 6 +++--- tools/RegressionSceneList.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py index ea8fc56..48790d6 100644 --- a/tools/RegressionSceneData.py +++ b/tools/RegressionSceneData.py @@ -8,7 +8,6 @@ import Sofa import Sofa.Gui -debug_info = False def is_simulated(node): if node.hasODESolver(): @@ -32,7 +31,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, disable_progress_bar = False): + epsilon = 0.0001, meca_in_mapping = True, dump_number_step = 1, disable_progress_bar = False, verbose = False): """ /// Path to the file scene to test std::string m_fileScenePath; @@ -63,6 +62,7 @@ def __init__(self, file_scene_path: str = None, file_ref_path: str = None, steps self.regression_failed = False self.root_node = None self.disable_progress_bar = disable_progress_bar + self.verbose = verbose def print_info(self): print("Test scene: " + self.file_scene_path + " vs " + self.file_ref_path + " using: " + str(self.steps) @@ -217,7 +217,7 @@ def compare_references(self): full_dist = np.linalg.norm(data_diff) error_by_dof = full_dist / float(data_diff.size) - if debug_info: + if self.verbose: 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.total_error[meca_id] = self.total_error[meca_id] + full_dist diff --git a/tools/RegressionSceneList.py b/tools/RegressionSceneList.py index 3ae6a5f..bb16ff7 100644 --- a/tools/RegressionSceneList.py +++ b/tools/RegressionSceneList.py @@ -61,7 +61,7 @@ def process_file(self): if len(values) == 5: scene_data = RegressionSceneData.RegressionSceneData(full_file_path, full_ref_file_path, values[1], values[2], values[3], values[4], - self.disable_progress_bar) + self.disable_progress_bar, self.verbose) #scene_data.printInfo() self.scenes_data_sets.append(scene_data) From aed79a728a8096e2460879a47eb6e2731b2d8021 Mon Sep 17 00:00:00 2001 From: epernod Date: Wed, 14 Jan 2026 23:19:20 +0100 Subject: [PATCH 2/5] Fix replay with gui --- tools/RegressionSceneData.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py index 48790d6..140cf33 100644 --- a/tools/RegressionSceneData.py +++ b/tools/RegressionSceneData.py @@ -6,8 +6,6 @@ import pathlib import Sofa -import Sofa.Gui - def is_simulated(node): if node.hasODESolver(): @@ -243,10 +241,17 @@ def compare_references(self): return True - def replayReferences(self): - Sofa.Gui.GUIManager.Init("myscene", "qglviewer") + def replay_references(self): + + # Import the GUI package + import SofaImGui + import Sofa.Gui + #supported_gui = Sofa.Gui.GUIManager.ListSupportedGUI(",") + self.root_node.bbox = "-10 -10 -10 10 10 10" + #print ("Supported GUIs are " + supported_gui) + Sofa.Gui.GUIManager.Init("myscene", "imgui") Sofa.Gui.GUIManager.createGUI(self.root_node, __file__) - Sofa.Gui.GUIManager.SetDimension(1080, 1080) + Sofa.Gui.GUIManager.SetDimension(1920, 1080) Sofa.Gui.GUIManager.MainLoop(self.root_node) Sofa.Gui.GUIManager.closeGUI() From f9d126c493f88777be91f0564b8c85b8cea042d0 Mon Sep 17 00:00:00 2001 From: epernod Date: Thu, 15 Jan 2026 00:04:56 +0100 Subject: [PATCH 3/5] Fix replay state using controller only and no compareState component (which could have been easier...) --- tools/RegressionSceneData.py | 38 ++++++++++++++++++++++++++++++++++-- tools/RegressionSceneList.py | 1 + 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py index 140cf33..d43db5f 100644 --- a/tools/RegressionSceneData.py +++ b/tools/RegressionSceneData.py @@ -20,6 +20,37 @@ def is_simulated(node): return False +class ReplayState(Sofa.Core.Controller): + def __init__(self, node, slave_mo, state_filename, **kwargs): + super().__init__(**kwargs) + self.node = node + self.slave_mo = slave_mo + self.keyframes = [] + self.frame_step = 0 + self.t_sim = 0.0 + + with gzip.open(state_filename, 'r') as zipfile: + self.ref_data = json.loads(zipfile.read().decode('utf-8')) + for key in self.ref_data: + self.keyframes.append(float(key)) + + if (self.keyframes[0] == 0.0): # frame 0.0 + tmp_position = np.asarray(self.ref_data[str(self.keyframes[0])]) + self.slave_mo.position = tmp_position.tolist() + self.frame_step = 1 + #print('nbr Frames', len(self.keyframes)) + + def onAnimateEndEvent(self, event): + dt = float(self.node.getRootContext().dt.value) + self.t_sim += dt + + if abs(self.t_sim - self.keyframes[self.frame_step]) < 0.000001: + tmp_position = np.asarray(self.ref_data[str(self.keyframes[self.frame_step])]) + self.slave_mo.position = tmp_position.tolist() + #print('tmp_position: ', tmp_position.shape) + self.frame_step += 1 + + class NumpyArrayEncoder(JSONEncoder): def default(self, obj): if isinstance(obj, np.ndarray): @@ -97,9 +128,12 @@ def parse_node(self, node, level = 0): def add_compare_state(self): counter = 0 for meca_obj in self.meca_objs: - _filename = self.file_ref_path + ".reference_" + str(counter) + "_" + meca_obj.name.value + "_mstate" + ".txt.gz" + #_filename = self.file_ref_path + ".reference_" + str(counter) + "_" + meca_obj.name.value + "_mstate" + ".txt.gz" + _filename = self.file_ref_path + ".reference_mstate_" + str(counter) + "_" + meca_obj.name.value + ".json.gz" - meca_obj.getContext().addObject('CompareState', filename=_filename) + compareNode = meca_obj.getContext().addChild("CompareStateNode_"+str(counter)) + cloudPoint = compareNode.addObject('VisualPointCloud', pointSize=10, drawMode="Point", color="green") + compareNode.addObject(ReplayState(node=compareNode, slave_mo=cloudPoint, state_filename=_filename)) counter = counter+1 diff --git a/tools/RegressionSceneList.py b/tools/RegressionSceneList.py index bb16ff7..867cd81 100644 --- a/tools/RegressionSceneList.py +++ b/tools/RegressionSceneList.py @@ -119,6 +119,7 @@ def compare_all_references(self): def replay_references(self, id_scene): self.scenes_data_sets[id_scene].load_scene() + self.scenes_data_sets[id_scene].add_compare_state() self.scenes_data_sets[id_scene].replay_references() From a614f0662173188dbe2095f90c917c88ea1f7ed7 Mon Sep 17 00:00:00 2001 From: epernod Date: Wed, 28 Jan 2026 17:47:11 +0100 Subject: [PATCH 4/5] some cleaning and use initRoot to avoid setting the bbox --- tools/RegressionSceneData.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/RegressionSceneData.py b/tools/RegressionSceneData.py index d43db5f..7d48107 100644 --- a/tools/RegressionSceneData.py +++ b/tools/RegressionSceneData.py @@ -38,7 +38,6 @@ def __init__(self, node, slave_mo, state_filename, **kwargs): tmp_position = np.asarray(self.ref_data[str(self.keyframes[0])]) self.slave_mo.position = tmp_position.tolist() self.frame_step = 1 - #print('nbr Frames', len(self.keyframes)) def onAnimateEndEvent(self, event): dt = float(self.node.getRootContext().dt.value) @@ -47,7 +46,6 @@ def onAnimateEndEvent(self, event): if abs(self.t_sim - self.keyframes[self.frame_step]) < 0.000001: tmp_position = np.asarray(self.ref_data[str(self.keyframes[self.frame_step])]) self.slave_mo.position = tmp_position.tolist() - #print('tmp_position: ', tmp_position.shape) self.frame_step += 1 @@ -128,6 +126,7 @@ def parse_node(self, node, level = 0): def add_compare_state(self): counter = 0 for meca_obj in self.meca_objs: + # Use this filename format to be compatible with previous version #_filename = self.file_ref_path + ".reference_" + str(counter) + "_" + meca_obj.name.value + "_mstate" + ".txt.gz" _filename = self.file_ref_path + ".reference_mstate_" + str(counter) + "_" + meca_obj.name.value + ".json.gz" @@ -152,7 +151,7 @@ def load_scene(self): print(f'Error while trying to load {self.file_scene_path}') raise RuntimeError else: - Sofa.Simulation.init(self.root_node) + Sofa.Simulation.initRoot(self.root_node) # prepare ref files per mecaObjs: self.parse_node(self.root_node, 0) @@ -280,9 +279,6 @@ def replay_references(self): # Import the GUI package import SofaImGui import Sofa.Gui - #supported_gui = Sofa.Gui.GUIManager.ListSupportedGUI(",") - self.root_node.bbox = "-10 -10 -10 10 10 10" - #print ("Supported GUIs are " + supported_gui) Sofa.Gui.GUIManager.Init("myscene", "imgui") Sofa.Gui.GUIManager.createGUI(self.root_node, __file__) Sofa.Gui.GUIManager.SetDimension(1920, 1080) From ea4b2d94b02fcc6f5c7c257b1addfe418ec894cd Mon Sep 17 00:00:00 2001 From: epernod Date: Fri, 30 Jan 2026 15:40:54 +0100 Subject: [PATCH 5/5] fix bad merge --- tools/RegressionSceneList.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tools/RegressionSceneList.py b/tools/RegressionSceneList.py index 4989829..f8e6004 100644 --- a/tools/RegressionSceneList.py +++ b/tools/RegressionSceneList.py @@ -72,13 +72,12 @@ def process_file(self): 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: - scene_data = RegressionSceneData.RegressionSceneData(full_file_path, full_ref_file_path, - values[1], values[2], values[3], values[4], - self.disable_progress_bar, self.verbose) + scene_data = RegressionSceneData.RegressionSceneData(full_file_path, full_ref_file_path, + values[1], values[2], values[3], values[4], + self.disable_progress_bar, self.verbose) - #scene_data.printInfo() - self.scenes_data_sets.append(scene_data) + #scene_data.printInfo() + self.scenes_data_sets.append(scene_data) def write_references(self, id_scene, print_log = False):