From dc6dfb47e016e2d9dc940fec0fc13d88635da9e1 Mon Sep 17 00:00:00 2001 From: SilvinWillemsen Date: Mon, 13 Apr 2026 18:08:05 +0200 Subject: [PATCH 1/2] First steps towards DeepONet with the new method. First tests in CHORAS show that the container spins up and seems to run the method, but breaks when trying to convert to .xlsx. --- deeponet_method/DeepONetInterface.py | 105 +++++++++++++++++++-------- deeponet_method/Dockerfile | 1 + deeponet_method/requirements.txt | 2 +- example_settings/don_setting.json | 86 ++++++++++++++++++++++ 4 files changed, 161 insertions(+), 33 deletions(-) create mode 100644 example_settings/don_setting.json diff --git a/deeponet_method/DeepONetInterface.py b/deeponet_method/DeepONetInterface.py index ce4fbfa..6c900e2 100644 --- a/deeponet_method/DeepONetInterface.py +++ b/deeponet_method/DeepONetInterface.py @@ -12,6 +12,9 @@ from deeponet_acoustics.end2end.train import train from deeponet_acoustics.end2end.inference import inference +from simulation_method_interface import SimulationMethod +from DGinterface import dg_method + def _resolve_path(path: str, base_dir: str) -> str: """ @@ -59,9 +62,9 @@ def _convert_relative_to_absolute_paths( ) # Construct derived paths - data["deeponet_inference_setup"]["validation_data_dir"] = os.path.join( + data["deeponet_inference_setup"]["test_data_dir"] = os.path.join( data["deeponet_train_setup"]["input_dir"], - data["deeponet_train_setup"]["testing_data_dir"], + data["deeponet_train_setup"]["val_data_dir"], ) data["deeponet_inference_setup"]["model_dir"] = os.path.join( data["deeponet_train_setup"]["output_dir"], data["deeponet_train_setup"]["id"] @@ -74,7 +77,7 @@ def _convert_relative_to_absolute_paths( return data -def _prepare_dg_json(json_file_path: str) -> str: +def _prepare_dg_json(json_file_path: str, dirname: str) -> str: """ Create a new JSON file from the configuration file to be used by the DG method. @@ -90,6 +93,9 @@ def _prepare_dg_json(json_file_path: str) -> str: data = json.load(file) # Create a new json file for DG + if not os.path.exists(os.path.join(dirname, "tmp")): + os.makedirs(os.path.join(dirname, "tmp")) + dg_json = os.path.join(os.path.join(dirname, "tmp"), "dg_tmp.json") # Copy the data of the DeepONet json into the DG json @@ -127,9 +133,16 @@ def _run_dg_simulation(json_file_path: str | Path) -> None: Args: json_file_path: Path to the JSON configuration file """ - gmsh.initialize() + should_finalise = False + if gmsh.isInitialized(): + should_finalise = True + else: + gmsh.initialize() + dg_method(json_file_path, save_results_to_json=False) - gmsh.finalize() + + if should_finalise: + gmsh.finalize() def _load_and_process_dg_results( @@ -277,7 +290,7 @@ def _prepare_validation_data( # Copy HDF5 validation data file_path_val_h5 = os.path.join( output_path, - settings["deeponet_train_setup"]["testing_data_dir"], + settings["deeponet_train_setup"]["val_data_dir"], f"src{source_index}", os.path.basename(train_h5_path), ) @@ -446,6 +459,35 @@ def _write_results_json( print(f"Results written to: {output_json_path}") +def _convert_from_CHORAS_json(json_file_path: str | Path, dirname: str): + + default_data_path = _resolve_path("app/models/data/deeponet_default_settings.json", Path(dirname).parent.parent) + with open(default_data_path, "r", encoding="utf-8") as default_file: + default_data = json.load(default_file) + + with open(json_file_path, "r", encoding="utf-8") as file: + data = json.load(file) + + default_data["absorption_coefficients"] = data["absorption_coefficients"] + default_data["msh_path"] = data["msh_path"] + default_data["geo_path"] = data["geo_path"] + + default_data["results"][0]["sourceX"] = data["results"][0]["sourceX"] + default_data["results"][0]["sourceY"] = data["results"][0]["sourceY"] + default_data["results"][0]["sourceZ"] = data["results"][0]["sourceZ"] + + data["simulationSettings"] = { + k.replace("don_", "dg_", 1): v + for k, v in data["simulationSettings"].items() + } + + default_data["dg_setup"]["simulationSettings"] = data["simulationSettings"] + default_data["should_cancel"] = False + + with open(json_file_path, "w") as file: + json.dump(default_data, file, indent=4) + + def deeponet_method(json_file_path: str | Path, output_json_path: str | Path = None): """ Execute the complete DeepONet pipeline: DG simulation, data preparation, training, and inference. @@ -466,6 +508,14 @@ def deeponet_method(json_file_path: str | Path, output_json_path: str | Path = N """ # Step 1: Convert relative paths to absolute paths dirname = os.path.dirname(__file__) + + with open(json_file_path, "r", encoding="utf-8") as file: + data = json.load(file) + + # This means that the data came from CHORAS + if "dg_setup" not in data: + _convert_from_CHORAS_json(json_file_path, dirname) + settings = _convert_relative_to_absolute_paths(json_file_path, dirname) # Set default output path if not provided @@ -475,7 +525,7 @@ def deeponet_method(json_file_path: str | Path, output_json_path: str | Path = N ) # Step 2: Run DG simulation - dg_json = _prepare_dg_json(json_file_path) + dg_json = _prepare_dg_json(json_file_path, dirname) _run_dg_simulation(dg_json) # Step 3: Load and process DG results @@ -501,7 +551,7 @@ def deeponet_method(json_file_path: str | Path, output_json_path: str | Path = N # Save training data to HDF5 file_path_train_h5 = os.path.join( output_path, - settings["deeponet_train_setup"]["training_data_dir"], + settings["deeponet_train_setup"]["train_data_dir"], f"src{i}", f"{output_filename}.h5", ) @@ -545,35 +595,26 @@ def deeponet_method(json_file_path: str | Path, output_json_path: str | Path = N # Step 7: Write results.json with DeepONet predictions _write_results_json(json_file_path, settings, output_json_path) +class DeepONetMethod(SimulationMethod): + def __init__(self): + super().__init__() + + def run_simulation(self, json_file_path): + deeponet_method(json_file_path) + if __name__ == "__main__": from HelperFunctions import ( - find_input_file_in_subfolders, - create_tmp_from_input, - save_results, - plot_dg_results, + plot_dg_results ) - # Clean up output folder - dirname = os.path.dirname(__file__) - output_dir = os.path.join(dirname, "headless_backend", "output") - if os.path.exists(output_dir): - for file in os.listdir(output_dir): - file_path = os.path.join(output_dir, file) - if os.path.isfile(file_path): - os.unlink(file_path) - - # Load the input file - file_name = "exampleInput_deeponet_acoustics.json" - json_tmp_file = create_tmp_from_input(file_name) - - # Define output path - results_json_path = os.path.join( - dirname, "headless_backend", "output", "results.json" - ) + json_file_path = os.environ.get("JSON_PATH", os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "common/exampleInput_deeponet_acoustics.json")) + + print(f"Running DeepONet method with JSON_PATH={json_file_path}") - # Run the complete DeepONet pipeline (includes DG simulation and results writing) - deeponet_method(json_tmp_file, results_json_path) + dg_method_object = DeepONetMethod() + dg_method_object.run_simulation(json_file_path) # Plot the results - plot_dg_results(results_json_path) \ No newline at end of file + plot_dg_results(json_file_path) + print("DeepONet container finished.") diff --git a/deeponet_method/Dockerfile b/deeponet_method/Dockerfile index 9296b59..0f2f861 100644 --- a/deeponet_method/Dockerfile +++ b/deeponet_method/Dockerfile @@ -19,6 +19,7 @@ RUN pip install --no-cache-dir -r requirements.txt # Copy the DE method interface and shared components COPY deeponet_method/DeepONetInterface.py . +COPY dg_method/DGinterface.py . COPY common/MeasurementRoom.geo . COPY common/MeasurementRoom.msh . COPY common/HelperFunctions.py . diff --git a/deeponet_method/requirements.txt b/deeponet_method/requirements.txt index 9d89ccc..0aec6bd 100644 --- a/deeponet_method/requirements.txt +++ b/deeponet_method/requirements.txt @@ -3,4 +3,4 @@ numpy-stl==3.1.1 scipy==1.14.0 gmsh==4.13.1 h5py -git+https://github.com/dtu-act/deeponet-acoustic-wave-prop.git@3d3fc5ee952756eedcd4fec3c3674ad829825c7e#egg=deeponet-acoustics \ No newline at end of file +git+https://github.com/dtu-act/deeponet-acoustic-wave-prop.git@3da1ae7bce73d558b005ef20b19a92cdce675e10 \ No newline at end of file diff --git a/example_settings/don_setting.json b/example_settings/don_setting.json new file mode 100644 index 0000000..4d44d4d --- /dev/null +++ b/example_settings/don_setting.json @@ -0,0 +1,86 @@ +{ + "type": "simulationSettings", + "options": [ + { + "name": "Freq. upper limit", + "description": "Until what frequency you want to simulate. Higher frequencies yield longer simulation times.", + "id": "don_freq_upper_limit", + "type": "integer", + "display": "text", + "min": 20, + "max": 4000, + "default": 200, + "step": 1, + "endAdornment": "Hz" + }, + { + "name": "Speed of sound", + "description": "The speed of sound in the medium (air).", + "id": "don_c0", + "type": "float", + "display": "text", + "min": 100, + "max": 500, + "default": 343, + "step": 1, + "endAdornment": "m/s" + }, + { + "name": "Air density", + "description": "The density of the medium (air).", + "id": "don_rho0", + "type": "float", + "display": "text", + "min": 0.001, + "max": 3, + "default": 1.213, + "step": 0.001, + "endAdornment": "kg/m^3" + }, + { + "name": "Impulse Response length", + "description": "The length of the impulse response you want to simulate.", + "id": "don_ir_length", + "type": "float", + "display": "text", + "min": 0.01, + "max": 5, + "default": 0.1, + "step": 0.01, + "endAdornment": "s" + }, + { + "name": "Poly order", + "description": "The polynomial order of the underlying DG method (only change if you know what you're doing).", + "id": "don_poly_order", + "type": "integer", + "display": "text", + "min": 2, + "max": 10, + "default": 4, + "step": 1 + }, + { + "name": "Points per wavelength", + "description": "The points per wavelength of the underlying DG method (only change if you know what you're doing).", + "id": "don_ppw", + "type": "integer", + "display": "text", + "min": 2, + "max": 10, + "default": 2, + "step": 1 + }, + { + "name": "CFL", + "description": "The Courant-Friedrichs-Lewy condition of the underlying DG method (only change if you know what you're doing).", + "id": "don_cfl", + "type": "float", + "display": "text", + "min": 0.001, + "max": 1, + "default": 1, + "step": 0.001 + } + ] +} \ No newline at end of file From ee408438f2e722dd6e6d0e5b74c6aec10f975143 Mon Sep 17 00:00:00 2001 From: SilvinWillemsen Date: Mon, 13 Apr 2026 18:10:08 +0200 Subject: [PATCH 2/2] Added DeepONet to the methods config as well now. --- methods-config.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/methods-config.json b/methods-config.json index 2683ca6..879ea12 100644 --- a/methods-config.json +++ b/methods-config.json @@ -19,6 +19,16 @@ "repositoryURL":"https://github.com/Building-acoustics-TU-Eindhoven/acousticDE/", "documentationURL":"https://building-acoustics-tu-eindhoven.github.io/acousticDE/index.html" }, + { + "simulationType": "DON", + "containerImage": "deeponet_image:latest", + "envVars": {}, + "label": "DeepONet", + "settings":"don_setting.json", + "entryFile":"DeepONetInterface.py", + "repositoryURL": "https://github.com/dtu-act/deeponet-acoustic-wave-prop/", + "documentationURL": "https://github.com/dtu-act/deeponet-acoustic-wave-prop/" + }, { "simulationType": "MyNewMethod", "containerImage": "mynewmethod_image:latest",