From cc080f44c1221cc5a8cd7197e78beba398bae9a3 Mon Sep 17 00:00:00 2001 From: Bray Moll Date: Sun, 25 May 2025 20:02:38 -0700 Subject: [PATCH 1/6] ensure data bounds is read from file --- src/flowvcutils/inigenerator.py | 139 +++++++++++++++++++++-------- tests/test_inigenerator.py | 153 +++++++++++++++++++------------- 2 files changed, 195 insertions(+), 97 deletions(-) diff --git a/src/flowvcutils/inigenerator.py b/src/flowvcutils/inigenerator.py index 8f0f563..5885341 100644 --- a/src/flowvcutils/inigenerator.py +++ b/src/flowvcutils/inigenerator.py @@ -5,7 +5,7 @@ import configparser from .utils import get_project_root import os - +import math logger = logging.getLogger(__name__) @@ -111,9 +111,19 @@ def streach_bounds(self, pt_min, pt_max, cell_size): raise ValueError("min must be less than max") if cell_size <= 0: raise ValueError("Cell Size must be >0") - while current_point < pt_max: - current_point = current_point + cell_size - n_pts = n_pts + 1 + + domain = pt_max - pt_min + # ceil the domain / cell_size to find how many cells needed to cover the domain: + n_cells = math.ceil(domain / cell_size) + + # compute the new max + new_max = pt_min + n_cells * cell_size + + # Optional rounding to reduce floating-point artifacts + # e.g. round to 7 or 8 decimal places as needed + new_max = round(new_max, 8) + + return (new_max, n_cells) new_max = current_point return (new_max, n_pts) @@ -205,39 +215,95 @@ def __init__(self, results_processor): self.load_config() self.__update_dict = {} - def set_data_range_defaults(self, cell_size, streach=True, manual_bounds=None): - if manual_bounds: + def set_data_range_defaults( + self, auto_range, cell_size, manual_bounds=None, streach=False + ): + """ + 1. If auto_range is True, compute Data_MeshBounds from .vtu. + Otherwise, leave Data_MeshBounds unchanged. + 2. If manual_bounds is provided, update FTLE_MeshBounds from it. + Otherwise, if auto_range is True, copy from Data_MeshBounds. + Otherwise, do not overwrite FTLE_MeshBounds. + """ - (x_range, y_range, z_range) = self.results_processor.set_data_range_manual( - manual_bounds[0], # (min_x, min_y, min_z) - manual_bounds[1], # (max_x, max_y, max_z) - streach, - cell_size, + def _update_bounds(prefix, x_range, y_range, z_range): + """Update __update_dict with mesh bounds for prefix (e.g. 'Data_MeshBounds').""" + self.__update_dict.update( + { + f"{prefix}.xmin": str(x_range[0]), + f"{prefix}.xmax": str(x_range[1]), + f"{prefix}.ymin": str(y_range[0]), + f"{prefix}.ymax": str(y_range[1]), + f"{prefix}.zmin": str(z_range[0]), + f"{prefix}.zmax": str(z_range[1]), + } ) - else: + + def _update_res(prefix): + """Update __update_dict with xres, yres, zres for prefix (e.g. 'FTLE_MeshBounds').""" + self.__update_dict.update( + { + f"{prefix}.xres": str(self.results_processor.x_points), + f"{prefix}.yres": str(self.results_processor.y_points), + f"{prefix}.zres": str(self.results_processor.z_points), + } + ) + + # 1) If auto_range => pull Data_MeshBounds from .vtu + if auto_range: x_range, y_range, z_range = self.results_processor.find_data_range( streach=streach, cell_size=cell_size ) + _update_bounds("Data_MeshBounds", x_range, y_range, z_range) - self.__update_dict.update( - { - "Data_MeshBounds.xmin": str(x_range[0]), - "Data_MeshBounds.xmax": str(x_range[1]), - "Data_MeshBounds.ymin": str(y_range[0]), - "Data_MeshBounds.ymax": str(y_range[1]), - "Data_MeshBounds.zmin": str(z_range[0]), - "Data_MeshBounds.zmax": str(z_range[1]), - "FTLE_MeshBounds.xmin": str(x_range[0]), - "FTLE_MeshBounds.xmax": str(x_range[1]), - "FTLE_MeshBounds.ymin": str(y_range[0]), - "FTLE_MeshBounds.ymax": str(y_range[1]), - "FTLE_MeshBounds.zmin": str(z_range[0]), - "FTLE_MeshBounds.zmax": str(z_range[1]), - "FTLE_MeshBounds.xres": str(self.results_processor.x_points), - "FTLE_MeshBounds.yres": str(self.results_processor.y_points), - "FTLE_MeshBounds.zres": str(self.results_processor.z_points), - } - ) + # 2) If manual_bounds => use it for FTLE_MeshBounds + if manual_bounds: + (ftle_xr, ftle_yr, ftle_zr) = self.results_processor.set_data_range_manual( + manual_bounds[0], + manual_bounds[1], + streach=streach, + cell_size=cell_size, + ) + _update_bounds("FTLE_MeshBounds", ftle_xr, ftle_yr, ftle_zr) + _update_res("FTLE_MeshBounds") + + # Otherwise, if auto_range is on but no manual bounds => copy from Data to FTLE + elif auto_range: + _update_bounds("FTLE_MeshBounds", x_range, y_range, z_range) + _update_res("FTLE_MeshBounds") + + # if manual_bounds: + + # (x_range, y_range, z_range) = self.results_processor.set_data_range_manual( + # manual_bounds[0], # (min_x, min_y, min_z) + # manual_bounds[1], # (max_x, max_y, max_z) + # streach, + # cell_size, + # ) + # else: + # x_range, y_range, z_range = self.results_processor.find_data_range( + # streach=streach, cell_size=cell_size + # ) + + # self.__update_dict.update( + # { + # "Data_MeshBounds.xmin": str(x_range[0]), + # "Data_MeshBounds.xmax": str(x_range[1]), + # "Data_MeshBounds.ymin": str(y_range[0]), + # "Data_MeshBounds.ymax": str(y_range[1]), + # "Data_MeshBounds.zmin": str(z_range[0]), + # "Data_MeshBounds.zmax": str(z_range[1]), + # "FTLE_MeshBounds.xmin": str(x_range[0]), + # "FTLE_MeshBounds.xmax": str(x_range[1]), + # "FTLE_MeshBounds.ymin": str(y_range[0]), + # "FTLE_MeshBounds.ymax": str(y_range[1]), + # "FTLE_MeshBounds.zmin": str(z_range[0]), + # "FTLE_MeshBounds.zmax": str(z_range[1]), + # "FTLE_MeshBounds.xres": str(self.results_processor.x_points), + # "FTLE_MeshBounds.yres": str(self.results_processor.y_points), + # "FTLE_MeshBounds.zres": str(self.results_processor.z_points), + # } + # ) def set_path_defaults(self): self.__update_dict.update( @@ -313,10 +379,13 @@ def write_config_file(self, file_path=None, file_name=None): def process_directory(self, auto_range, cell_size, direction, manual_bounds=None): self.set_path_defaults() - if auto_range: - self.set_data_range_defaults( - cell_size=cell_size, manual_bounds=manual_bounds - ) + # if auto_range: + self.set_data_range_defaults( + auto_range=auto_range, + cell_size=cell_size, + streach=True, + manual_bounds=manual_bounds, + ) if direction == "backward": self.set_backwards_defaults() elif direction == "forward": diff --git a/tests/test_inigenerator.py b/tests/test_inigenerator.py index 040e8a6..8bd756b 100644 --- a/tests/test_inigenerator.py +++ b/tests/test_inigenerator.py @@ -396,71 +396,100 @@ def test_integration_full_config(create_sample_vtu_file): assert not (Output_TEnd < Data_TMin) -def test_integration_manual_bounds(): +def test_integration_manual_bounds(create_sample_vtu_file): """ - Test that manual bounds are set correctly and the .in file picks them up, - rather than reading from a .vtu file. + Test that if auto_range is True, the Data_MeshBounds come from the .vtu file, + but the FTLE_MeshBounds and mesh resolution are driven by manual_bounds. """ - # Arbitrary example bounds: x in [0.0,1.0], y in [2.0,3.0], z in [4.0,4.2] + # Our sample_vtu has points at (1,2,3), (4,5,6), and (-1,-2,-3), + # so we expect Data_MeshBounds to be: + # X in [-1.0, 4.0] + # Y in [-2.0, 5.0] + # Z in [-3.0, 6.0] + # Meanwhile, the FTLE_MeshBounds should match the manual bounds. + vtu_file = create_sample_vtu_file + directory = Path(vtu_file).parent.parent + (directory / "input_bin").mkdir() + + # Manual bounds for FTLE: X in [0..1], Y in [2..3], Z in [4..4.2] # with cell_size=0.1 => xres=10, yres=10, zres=2 manual_bounds = ((0.0, 2.0, 4.0), (0.95, 3.0, 4.16)) cell_size = 0.1 - with TemporaryDirectory() as temp_dir: - os.mkdir(os.path.join(temp_dir, "input_bin")) - # Call the generator, passing our manual bounds - inigenerator_main( - directory=temp_dir, - auto_range=True, # "auto" sizing, but overridden by manual_bounds - cell_size=cell_size, - direction="backward", - batch=False, - manual_bounds=manual_bounds, - ) - - # The generator should produce an .in file named after the directory - dir_name = os.path.basename(temp_dir) - in_file_name = ( - f"{dir_name}.in" if not dir_name.endswith("_") else f"{dir_name[:-1]}.in" - ) - in_file = Path(temp_dir) / "input_bin" / in_file_name - - # Ensure file was created - assert in_file.exists(), f"{in_file} was not created." - - # Read certain fields from the .in file - var_list = [ - "data_meshbounds.xmin", - "data_meshbounds.xmax", - "data_meshbounds.ymin", - "data_meshbounds.ymax", - "data_meshbounds.zmin", - "data_meshbounds.zmax", - "ftle_meshbounds.xres", - "ftle_meshbounds.yres", - "ftle_meshbounds.zres", - ] - config_values = load_config(str(in_file), var_list) - - # Convert to float/int as appropriate - xmin = float(config_values["data_meshbounds.xmin"]) - xmax = float(config_values["data_meshbounds.xmax"]) - ymin = float(config_values["data_meshbounds.ymin"]) - ymax = float(config_values["data_meshbounds.ymax"]) - zmin = float(config_values["data_meshbounds.zmin"]) - zmax = float(config_values["data_meshbounds.zmax"]) - xres = int(config_values["ftle_meshbounds.xres"]) - yres = int(config_values["ftle_meshbounds.yres"]) - zres = int(config_values["ftle_meshbounds.zres"]) - - # Check bounding box: cell_size=0.1 => expected domain [0..1], [2..3], [4..4.2] - # => xres=10, yres=10, zres=2 - assert math.isclose(xmin, 0.0), f"Expected 0.0, got {xmin}" - assert math.isclose(xmax, 1.0), f"Expected 1.0, got {xmax}" - assert math.isclose(ymin, 2.0), f"Expected 2.0, got {ymin}" - assert math.isclose(ymax, 3.0), f"Expected 3.0, got {ymax}" - assert math.isclose(zmin, 4.0), f"Expected 4.0, got {zmin}" - assert math.isclose(zmax, 4.2), f"Expected 4.2, got {zmax}" - assert xres == 10, f"Expected xres=10, got {xres}" - assert yres == 10, f"Expected yres=10, got {yres}" - assert zres == 2, f"Expected zres=2, got {zres}" + # Call inigenerator with auto_range=True and the manual bounds + inigenerator_main( + directory=str(directory), + auto_range=True, + cell_size=cell_size, + direction="backward", + batch=False, + manual_bounds=manual_bounds, + ) + + # The generator should produce an .in file named after the directory + dir_name = directory.name + in_file_name = dir_name[:-1] + ".in" if dir_name.endswith("_") else f"{dir_name}.in" + in_file = directory / "input_bin" / in_file_name + + # Ensure file was created + assert in_file.exists(), f"{in_file} was not created." + + # Read certain fields from the .in file + var_list = [ + "data_meshbounds.xmin", + "data_meshbounds.xmax", + "data_meshbounds.ymin", + "data_meshbounds.ymax", + "data_meshbounds.zmin", + "data_meshbounds.zmax", + "ftle_meshbounds.xmin", + "ftle_meshbounds.xmax", + "ftle_meshbounds.ymin", + "ftle_meshbounds.ymax", + "ftle_meshbounds.zmin", + "ftle_meshbounds.zmax", + "ftle_meshbounds.xres", + "ftle_meshbounds.yres", + "ftle_meshbounds.zres", + ] + config_values = load_config(str(in_file), var_list) + + # Convert to float/int as appropriate + data_xmin = float(config_values["data_meshbounds.xmin"]) + data_xmax = float(config_values["data_meshbounds.xmax"]) + data_ymin = float(config_values["data_meshbounds.ymin"]) + data_ymax = float(config_values["data_meshbounds.ymax"]) + data_zmin = float(config_values["data_meshbounds.zmin"]) + data_zmax = float(config_values["data_meshbounds.zmax"]) + + ftle_xmin = float(config_values["ftle_meshbounds.xmin"]) + ftle_xmax = float(config_values["ftle_meshbounds.xmax"]) + ftle_ymin = float(config_values["ftle_meshbounds.ymin"]) + ftle_ymax = float(config_values["ftle_meshbounds.ymax"]) + ftle_zmin = float(config_values["ftle_meshbounds.zmin"]) + ftle_zmax = float(config_values["ftle_meshbounds.zmax"]) + + ftle_xres = int(config_values["ftle_meshbounds.xres"]) + ftle_yres = int(config_values["ftle_meshbounds.yres"]) + ftle_zres = int(config_values["ftle_meshbounds.zres"]) + + # Confirm Data_MeshBounds came from the sample_vtu_file + assert math.isclose(data_xmin, -1.0), f"Expected Data X-min = -1.0, got {data_xmin}" + assert math.isclose(data_xmax, 4.0), f"Expected Data X-max = 4.0, got {data_xmax}" + assert math.isclose(data_ymin, -2.0), f"Expected Data Y-min = -2.0, got {data_ymin}" + assert math.isclose(data_ymax, 5.0), f"Expected Data Y-max = 5.0, got {data_ymax}" + assert math.isclose(data_zmin, -3.0), f"Expected Data Z-min = -3.0, got {data_zmin}" + assert math.isclose(data_zmax, 6.0), f"Expected Data Z-max = 6.0, got {data_zmax}" + + # Confirm FTLE_MeshBounds came from manual_bounds + # We specified (0.0..~1.0), (2.0..3.0), (4.0..4.2) with cell_size=0.1 => xres=10, yres=10, zres=2 + assert math.isclose(ftle_xmin, 0.0), f"Expected FTLE X-min = 0.0, got {ftle_xmin}" + assert math.isclose(ftle_xmax, 1.0), f"Expected FTLE X-max ~ 1.0, got {ftle_xmax}" + assert math.isclose(ftle_ymin, 2.0), f"Expected FTLE Y-min = 2.0, got {ftle_ymin}" + assert math.isclose(ftle_ymax, 3.0), f"Expected FTLE Y-max = 3.0, got {ftle_ymax}" + assert math.isclose(ftle_zmin, 4.0), f"Expected FTLE Z-min = 4.0, got {ftle_zmin}" + assert math.isclose(ftle_zmax, 4.2), f"Expected FTLE Z-max = 4.2, got {ftle_zmax}" + + assert ftle_xres == 10, f"Expected FTLE xres=10, got {ftle_xres}" + assert ftle_yres == 10, f"Expected FTLE yres=10, got {ftle_yres}" + assert ftle_zres == 2, f"Expected FTLE zres=2, got {ftle_zres}" From 5bc698cdaefed4202fd09175b7b1a3408109e187 Mon Sep 17 00:00:00 2001 From: Bray Moll Date: Sun, 25 May 2025 20:21:33 -0700 Subject: [PATCH 2/6] remove unreachable code and cleanup commented sections. --- src/flowvcutils/inigenerator.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/flowvcutils/inigenerator.py b/src/flowvcutils/inigenerator.py index 5885341..3529d0c 100644 --- a/src/flowvcutils/inigenerator.py +++ b/src/flowvcutils/inigenerator.py @@ -124,8 +124,6 @@ def streach_bounds(self, pt_min, pt_max, cell_size): new_max = round(new_max, 8) return (new_max, n_cells) - new_max = current_point - return (new_max, n_pts) def set_data_range_manual(self, min_xyz, max_xyz, streach=False, cell_size=0): # Manually set From 57e9734e17b3a6787ae397557b5cb45047934f4b Mon Sep 17 00:00:00 2001 From: Bray Moll Date: Sun, 25 May 2025 20:23:21 -0700 Subject: [PATCH 3/6] remove unreachable code (ci failure) and remove commented code --- src/flowvcutils/inigenerator.py | 37 +-------------------------------- 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/src/flowvcutils/inigenerator.py b/src/flowvcutils/inigenerator.py index 3529d0c..411611b 100644 --- a/src/flowvcutils/inigenerator.py +++ b/src/flowvcutils/inigenerator.py @@ -106,7 +106,6 @@ def streach_bounds(self, pt_min, pt_max, cell_size): """ current_point = pt_min - n_pts = 0 if current_point >= pt_max: raise ValueError("min must be less than max") if cell_size <= 0: @@ -119,8 +118,7 @@ def streach_bounds(self, pt_min, pt_max, cell_size): # compute the new max new_max = pt_min + n_cells * cell_size - # Optional rounding to reduce floating-point artifacts - # e.g. round to 7 or 8 decimal places as needed + # Rounding to 8 decimal places to reduce floating-point artifacts new_max = round(new_max, 8) return (new_max, n_cells) @@ -270,39 +268,6 @@ def _update_res(prefix): _update_bounds("FTLE_MeshBounds", x_range, y_range, z_range) _update_res("FTLE_MeshBounds") - # if manual_bounds: - - # (x_range, y_range, z_range) = self.results_processor.set_data_range_manual( - # manual_bounds[0], # (min_x, min_y, min_z) - # manual_bounds[1], # (max_x, max_y, max_z) - # streach, - # cell_size, - # ) - # else: - # x_range, y_range, z_range = self.results_processor.find_data_range( - # streach=streach, cell_size=cell_size - # ) - - # self.__update_dict.update( - # { - # "Data_MeshBounds.xmin": str(x_range[0]), - # "Data_MeshBounds.xmax": str(x_range[1]), - # "Data_MeshBounds.ymin": str(y_range[0]), - # "Data_MeshBounds.ymax": str(y_range[1]), - # "Data_MeshBounds.zmin": str(z_range[0]), - # "Data_MeshBounds.zmax": str(z_range[1]), - # "FTLE_MeshBounds.xmin": str(x_range[0]), - # "FTLE_MeshBounds.xmax": str(x_range[1]), - # "FTLE_MeshBounds.ymin": str(y_range[0]), - # "FTLE_MeshBounds.ymax": str(y_range[1]), - # "FTLE_MeshBounds.zmin": str(z_range[0]), - # "FTLE_MeshBounds.zmax": str(z_range[1]), - # "FTLE_MeshBounds.xres": str(self.results_processor.x_points), - # "FTLE_MeshBounds.yres": str(self.results_processor.y_points), - # "FTLE_MeshBounds.zres": str(self.results_processor.z_points), - # } - # ) - def set_path_defaults(self): self.__update_dict.update( { From a57ede198ac357fc2c21b2c8f98e20cc6b75a247 Mon Sep 17 00:00:00 2001 From: Bray Moll Date: Sun, 25 May 2025 20:30:36 -0700 Subject: [PATCH 4/6] fix linting errors --- src/flowvcutils/inigenerator.py | 2 +- tests/test_inigenerator.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/flowvcutils/inigenerator.py b/src/flowvcutils/inigenerator.py index 411611b..a3a6cce 100644 --- a/src/flowvcutils/inigenerator.py +++ b/src/flowvcutils/inigenerator.py @@ -236,7 +236,7 @@ def _update_bounds(prefix, x_range, y_range, z_range): ) def _update_res(prefix): - """Update __update_dict with xres, yres, zres for prefix (e.g. 'FTLE_MeshBounds').""" + """Update __update_dict with xres, yres, zres for prefix).""" self.__update_dict.update( { f"{prefix}.xres": str(self.results_processor.x_points), diff --git a/tests/test_inigenerator.py b/tests/test_inigenerator.py index 8bd756b..b186321 100644 --- a/tests/test_inigenerator.py +++ b/tests/test_inigenerator.py @@ -482,7 +482,8 @@ def test_integration_manual_bounds(create_sample_vtu_file): assert math.isclose(data_zmax, 6.0), f"Expected Data Z-max = 6.0, got {data_zmax}" # Confirm FTLE_MeshBounds came from manual_bounds - # We specified (0.0..~1.0), (2.0..3.0), (4.0..4.2) with cell_size=0.1 => xres=10, yres=10, zres=2 + # We specified (0.0..~1.0), (2.0..3.0), (4.0..4.2) + # with cell_size=0.1 => xres=10, yres=10, zres=2 assert math.isclose(ftle_xmin, 0.0), f"Expected FTLE X-min = 0.0, got {ftle_xmin}" assert math.isclose(ftle_xmax, 1.0), f"Expected FTLE X-max ~ 1.0, got {ftle_xmax}" assert math.isclose(ftle_ymin, 2.0), f"Expected FTLE Y-min = 2.0, got {ftle_ymin}" From 3aca5eedd01e263ea645183c40546d2c62df6f83 Mon Sep 17 00:00:00 2001 From: Bray Moll Date: Sun, 25 May 2025 20:34:40 -0700 Subject: [PATCH 5/6] linting attempt agiain --- src/flowvcutils/jsonlogger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flowvcutils/jsonlogger.py b/src/flowvcutils/jsonlogger.py index 64b4d5b..bc5ad82 100644 --- a/src/flowvcutils/jsonlogger.py +++ b/src/flowvcutils/jsonlogger.py @@ -102,7 +102,7 @@ def settup_logging(config_file_path=None): config = json.load(f_in) # for handler_name, handler in config["handlers"].items(): - for handler_name, handler in config["handlers"].items(): + for _handler_name, handler in config["handlers"].items(): if "filename" in handler: handler["filename"] = str(logs_dir / pathlib.Path(handler["filename"]).name) From 205ecc04837545104ec6dda6af6790805f85386b Mon Sep 17 00:00:00 2001 From: Bray Moll Date: Sun, 25 May 2025 20:35:43 -0700 Subject: [PATCH 6/6] and agian --- src/flowvcutils/inigenerator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flowvcutils/inigenerator.py b/src/flowvcutils/inigenerator.py index a3a6cce..81c2412 100644 --- a/src/flowvcutils/inigenerator.py +++ b/src/flowvcutils/inigenerator.py @@ -223,7 +223,7 @@ def set_data_range_defaults( """ def _update_bounds(prefix, x_range, y_range, z_range): - """Update __update_dict with mesh bounds for prefix (e.g. 'Data_MeshBounds').""" + """Update __update_dict with mesh bounds for prefix').""" self.__update_dict.update( { f"{prefix}.xmin": str(x_range[0]),