Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3278cd0
Ran copier
Matteo-Scerbo May 11, 2026
82822c3
Added RAVES dependency
Matteo-Scerbo May 11, 2026
e1bfb9d
It works!
Matteo-Scerbo May 11, 2026
c064593
Wavefront conversion work, but materials are not included
Matteo-Scerbo May 11, 2026
165075f
Test file didn't have materials. That wasn't the (only) problem.
Matteo-Scerbo May 11, 2026
877aff7
Found material assignments
Matteo-Scerbo May 12, 2026
004bc0e
Mesh conversion works!
Matteo-Scerbo May 12, 2026
472557a
IT WORKS
Matteo-Scerbo May 12, 2026
c58ca03
Cleaned up
Matteo-Scerbo May 12, 2026
b306380
Docker setup
Matteo-Scerbo May 12, 2026
ef87f46
Released raves on PyPI (Docker still doesn't work though)
Matteo-Scerbo May 12, 2026
c25432f
Adapted mesh conversion to the format currently used in CHORAS
Matteo-Scerbo May 13, 2026
344216d
Tests pass with the new test inputs.
Matteo-Scerbo May 13, 2026
a160c03
Simulation ran in docker!
Matteo-Scerbo May 13, 2026
c8f6922
Request later version of raves
Matteo-Scerbo May 13, 2026
b610bb5
Reconfigured mesh conversion to use gmsh
Matteo-Scerbo May 18, 2026
fcb7547
Revised comments
Matteo-Scerbo May 18, 2026
f6a3752
Revised comments
Matteo-Scerbo May 18, 2026
2dc6872
Updated progress bar.
Matteo-Scerbo May 19, 2026
5731a66
Removed completed TODO
Matteo-Scerbo May 20, 2026
515dc85
Removed .msh from tests
Matteo-Scerbo May 22, 2026
ad483c9
Updated test room to have multiple patches with the same material (to…
Matteo-Scerbo May 22, 2026
6a6cdcf
Extended basic test
Matteo-Scerbo May 22, 2026
746817e
Assume the list of receivers is the same for all sources.
Matteo-Scerbo Jun 9, 2026
a89a5b3
Added more varied tests.
Matteo-Scerbo Jun 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions example_settings/modart_setting.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
{
"type": "simulationSettings",
"options": [
{
"name": "Response duration",
"id": "durat",
"type": "float",
"display": "text",
"min": 1e-1,
"max": 1e1,
"default": 1e0,
"step": 1e-1,
"endAdornment": "s"
},
{
"name": "Echogram sample rate",
"id": "f_e",
"type": "float",
"display": "text",
"min": 5e1,
"max": 5e4,
"default": 5e3,
"step": 5e1,
"endAdornment": "Hz"
},
{
"name": "T60 threshold",
"id": "T60",
"type": "float",
"display": "text",
"min": 1e-3,
"max": 1e1,
"default": 1e-1,
"step": 1e-2,
"endAdornment": "s"
},
{
"name": "Max slopes",
"id": "slopes",
"type": "int",
"display": "text",
"min": 1,
"max": 100,
"default": 10,
"step": 1
},
{
"name": "Air humidity",
"id": "humi",
"type": "float",
"display": "text",
"min": 0.0,
"max": 100.0,
"default": 50.0,
"step": 5.0,
"endAdornment": "%"
},
{
"name": "Air temperature",
"id": "temp",
"type": "float",
"display": "text",
"min": -100.0,
"max": 100.0,
"default": 20.0,
"step": 1.0,
"endAdornment": "°C"
},
{
"name": "Atmospheric pressure",
"id": "pres",
"type": "float",
"display": "text",
"min": 50.0,
"max": 150.0,
"default": 100.0,
"step": 0.1,
"endAdornment": "kPa"
},
{
"name": "Points per square meter",
"id": "ppsm",
"type": "float",
"display": "text",
"min": 0,
"max": 100.0,
"default": 30.0,
"step": 0.1
},
{
"name": "Rays per hemisphere",
"id": "rays",
"type": "int",
"display": "text",
"min": 10,
"max": 10000,
"default": 1000,
"step": 100
},
{
"name": "Max parallel processes",
"id": "pool",
"type": "int",
"display": "text",
"min": 1,
"max": 10000,
"default": 4,
"step": 1
}
]
}
10 changes: 10 additions & 0 deletions methods-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "MoDART",
"containerImage": "modart_image:latest",
"envVars": {},
"label": "MoD-ART",
"entryFile":"modart_interface.py",
"settings":"modart_setting.json",
"repositoryURL":"https://github.com/IoSR-Surrey/MoD-ART/",
"documentationURL":"https://github.com/IoSR-Surrey/MoD-ART/blob/master/example%20usage/Tutorial.ipynb"
},
{
"simulationType": "MyNewMethod",
"containerImage": "mynewmethod_image:latest",
Expand Down
22 changes: 22 additions & 0 deletions modart_method/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM python:3.11.13-slim

# Set working directory
WORKDIR /app

# Install system dependencies for mesh generation and scientific computing
RUN apt-get update && apt-get install -y \
git \
build-essential \
gmsh \
&& rm -rf /var/lib/apt/lists/*

# Copy method package directory
COPY modart_method /app/modart_method

# Install the method package
RUN pip install --no-cache-dir /app/modart_method

WORKDIR /app/modart_method

# Default command to run the containerized MoDART method
CMD ["python", "-m", "modart_interface"]
21 changes: 21 additions & 0 deletions modart_method/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2025, Matteo Scerbo

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 changes: 19 additions & 0 deletions modart_method/modart_interface/__cli__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""CLI module for MoDART method."""
import os
from .modart_interface import MoDARTMethod


def main() -> None:
"""Run the MoDART method simulation."""
# JSON path in the uploads folder. This variable is set for the
# container when it is started up.
json_file_path = os.environ.get("JSON_PATH")

print(f"Running MoDART method with JSON_PATH={json_file_path}")
modart_method_object = MoDARTMethod(json_file_path)
modart_method_object.run_simulation()

# Save the results to a separate file
modart_method_object.save_results()

print("MoDART container finished.")
8 changes: 8 additions & 0 deletions modart_method/modart_interface/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""MoDARTMethod package."""
from .__main__ import main
from .modart_interface import MoDARTMethod

__all__ = [
"main",
"MoDARTMethod"
]
5 changes: 5 additions & 0 deletions modart_method/modart_interface/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Main module for MoDART method."""
from .__cli__ import main

if __name__ == "__main__":
main()
92 changes: 92 additions & 0 deletions modart_method/modart_interface/definition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""Base class implementation of the SimulationMethod interface class."""
from abc import ABC, abstractmethod
from pathlib import Path
import time

import requests


class SimulationMethod(ABC):
"""Abstract base class for simulation methods.

This class serves as a template for methods required to run a simulation
and return results to the simulation service executor.

"""

def __init__(self, input_json_path: str | Path | None):
"""Initialize the simulation method.

Parameters
----------
input_json_path : str | Path | None, optional
The path to the input JSON file, by default None

Raises
------
FileNotFoundError
If the input JSON file does not exist.

"""
if input_json_path is None or (
isinstance(input_json_path, str) and input_json_path == ""):
raise FileNotFoundError("input_json_path cannot be None or empty")

input_path = Path(input_json_path)
if not input_path.exists():
raise FileNotFoundError(
f"Input JSON file not found: {input_json_path}")

self._input_json_path = input_json_path

@property
def input_json_path(self) -> str | Path:
"""The input JSON file."""
return self._input_json_path

@abstractmethod
def run_simulation(self):
"""Run the simulation for the given a JSON file."""
pass

def save_results(
self,
url="http://host.docker.internal:5001/receive",
max_retries=5,
delay=2,
):
"""Return the results back to the simulation service executor.

Parameters
----------
url : str, optional
The URL of the results server,
by default "http://host.docker.internal:5001/receive" which
is the default address for local executrion via Docker.
max_retries : int, optional
The maximum number of retries if the request fails, by default 5
delay : int, optional
The delay in seconds between retries, by default 2

"""

json_tmp_file = self.input_json_path
for attempt in range(1, max_retries + 1):
try:
with open(json_tmp_file, "rb") as f:
response = requests.post(url, files={"file": f})

if response.status_code == 200:
print("Successfully sent file.")
return True

print(
f"Attempt {attempt}: ",
f"Server returned {response.status_code}")
except requests.RequestException as exc:
print(f"Attempt {attempt}: Request failed - {exc}")

time.sleep(delay)

print("Max retries reached. Giving up.")
return False
Loading