From 511a116052fb06db355b62448185c701bc2d271f Mon Sep 17 00:00:00 2001 From: blttkgl Date: Wed, 13 May 2026 14:35:39 +0300 Subject: [PATCH 1/2] Add multiregion function object reader support (#33) --- .../coolingCylinder2D/coolingCylinder2D.py | 94 +++++++++++++++++++ flowboost/openfoam/data/base.py | 38 ++++++-- tests/flowboost/openfoam/test_data_unit.py | 39 ++++++++ 3 files changed, 162 insertions(+), 9 deletions(-) create mode 100644 examples/coolingCylinder2D/coolingCylinder2D.py diff --git a/examples/coolingCylinder2D/coolingCylinder2D.py b/examples/coolingCylinder2D/coolingCylinder2D.py new file mode 100644 index 0000000..e57fb3b --- /dev/null +++ b/examples/coolingCylinder2D/coolingCylinder2D.py @@ -0,0 +1,94 @@ +from __future__ import annotations + +import warnings +from pathlib import Path + +import coloredlogs +import polars as pl + +from flowboost import ( + Case, + Constraint, + Dictionary, + Dimension, + Manager, + Objective, + Session, +) + +def averageT(case: Case): + """Calculate the lift to drag ratio from simulation results.""" + dataframe = case.data.simple_function_object_reader("fluid/cylinderT") + + if dataframe is None: + return None + return ( + dataframe.select(pl.last("areaAverage(T)")).item() + ) + + + + + +if __name__ == "__main__": + coloredlogs.install(level="INFO") + + # --- Session --- + session = Session( + name="coolingCylinder2D", + data_dir=Path("flowboost_data"), + clone_method="copy", + max_evaluations=50, + bo_concurrency=3 + ) + + # --- Template case --- + cooling_case = Case.from_tutorial( + "multiRegion/CHT/coolingCylinder2D", + Path(session.data_dir, "coolingCylinder2D_template"), + method="copy", + ) + cooling_case.dictionary("system/controlDict").entry("writeInterval").set("20") + + session.attach_template_case(case=cooling_case) + + # --- Objectives --- + + objective = Objective( + name="averageT", + minimize=False, + objective_function=averageT, + ) + + + + # --- Search space --- + DICT_FILE = "system/blockMeshDict" + + radius_dim = Dimension.range( + name="cylinderRadius", + link=Dictionary.link(DICT_FILE).entry("cylinderRadius"), + lower=-0.001, + upper=0.01, + ) + + + + session.configure_optimization( + objectives=[objective], + search_space=[radius_dim] + ) + + # --- Job manager --- + session.job_manager = session.job_manager or Manager.create( + scheduler="Local", + wdir=session.data_dir, + job_limit=1, + ) + session.job_manager.monitoring_interval = 10 + + # --- Run --- + session.backend.initialization_trials = 10 + session.clean_pending_cases() + session.start() + diff --git a/flowboost/openfoam/data/base.py b/flowboost/openfoam/data/base.py index 621e6e9..b74fe28 100644 --- a/flowboost/openfoam/data/base.py +++ b/flowboost/openfoam/data/base.py @@ -97,21 +97,39 @@ def discover_function_objects(self) -> dict[str, dict[str, list[Path]]]: function_objects = {} for function_dir in filter(Path.is_dir, self.post_processing_path.iterdir()): - time_dirs = self._time_dirs_for_function_object(function_dir) - - function_objects[function_dir.name] = { - time_dir.name: sorted( - (path for path in time_dir.iterdir() if path.is_file()), - key=lambda path: path.name, - ) - for time_dir in time_dirs - } + direct_outputs = self._files_by_time_directory(function_dir) + if direct_outputs: + function_objects[function_dir.name] = direct_outputs + + # Multi-region function objects often add one extra nesting level: + # postProcessing///