Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 7 additions & 1 deletion .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,10 @@ jobs:
run: python -m pip install -r requirements.txt

- name: Run tests
run: python -m pytest -v tests/unit/services/ tests/unit/models
run: |
python -m pytest -v \
tests/unit/services/ \
tests/unit/models \
--ignore=tests/unit/executors/ \
--ignore=tests/unit/services/test_discovery_service.py \
--ignore=tests/unit/services/test_run_solver.py
46 changes: 42 additions & 4 deletions app/services/auralization_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,15 +288,25 @@ def run_auralization(auralizationId: int) -> None:

logger.debug("run auralization calculation")

#TODO: fix behavior for DG auralization, DG method output format
# should be changed. We want a single universal auralization method,
# without having to switch logic between them for each simulation method.
match simulation.simulationMethod:
case "DE":
_, _ = auralization_calculation(signal_file_name, pressure_file_name, wav_output_file_name)
case "DG":
_, _ = auralization_calculation_DG(signal_file_name, pressure_file_name, wav_output_file_name)

case _:
#TODO: We want a single universal auralization method,
# without having to switch logic between them for each simulation method.
# This will be implemented in the function mono_aural_auralization, which will be a
# general convolution-based auralization method using the RIR.
# This method does not rely on the pressure.csv file, but the wav file directly
pressure_file_name_wav = os.path.join(
DefaultConfig.UPLOAD_FOLDER_NAME, export.name.replace(".xlsx", ".wav")
)
mono_aural_auralization(
signal_file_name,
pressure_file_name_wav,
wav_output_file_name
)
Comment on lines 291 to +309

auralization.status = Status.Completed

Expand All @@ -310,6 +320,34 @@ def run_auralization(auralizationId: int) -> None:
abort(400, "Error running this auralization")


def mono_aural_auralization(
signal_file_name: str,
impulse_response_file_name_wav: str,
wav_output_file_name: str,
) -> None:
"""Create a mono-aural auralization by convolution.

If the sampling rates do not match, the impulse response is resampled to
match the sampling rate of the dry input signal.

Parameters
----------
signal_file_name : str
The dry input signal file name (wav format).
impulse_response_file_name_wav : str
The impulse response file name (wav format).
wav_output_file_name : str
The convolved output signal file name (wav format).
"""

import pyfar as pf
dry_signal = pf.io.read_audio(signal_file_name)
rir = pf.io.read_audio(impulse_response_file_name_wav)
rir_resampled = pf.dsp.resample(rir, dry_signal.sampling_rate)
convolved_signal = pf.dsp.convolve(rir_resampled, dry_signal)
pf.io.write_audio(convolved_signal, wav_output_file_name)


# TODO: too long code, refactor this function
def auralization_calculation_DG(
signal_file_name: Optional[str], impulse_response: str, wav_output_file_name: Optional[str] = None
Expand Down
122 changes: 75 additions & 47 deletions app/services/simulation_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ def start_solver_task(simulation_id):
"geo_path": geo_path,
"results": results_container,
"task_id": -1,
"fs_auralization": 44100
},
indent=4,
)
Expand Down Expand Up @@ -421,59 +422,86 @@ def run_solver(simulation_run_id: int, json_path: str):

cancel_flag_path = Path(json_path).parent / f"{result_container['task_id']}.cancel"

# auralization: generate impulse response wav file
# TODO: move the auralization calculation to DE and write that
# to the JSON so that everything can be handled by the current
# default case and we can get rid of the match case.
match simulation_method:
case "DE":
# TODO: This function is not a general auralization function and should be renamed
imp_tot, fs = auralization_calculation(
None,
json_path.replace(".json", "_pressure.csv"),
json_path.replace(".json", ".wav"),
)

# this should be the only thing getting executed
case _:
import numpy as np

with open(json_path, "r") as json_file:
result_container = json.load(json_file)

imp_tot = np.array(result_container["results"][0]["responses"][0]["receiverResults"])

with open(json_path, "r") as json_file:
input_data = json.load(json_file)
if "sampling_rate" in input_data["simulationSettings"]:
fs = input_data["simulationSettings"]["sampling_rate"]
else:
fs = input_data["fs_auralization"] # 44100 by default

rir_wav_file_name = json_path.replace(".json", ".wav")

import pyfar as pf
if imp_tot is None or len(imp_tot) == 0:
logger.warning("Impulse response data is empty or missing")
imp_tot = np.zeros(44100) # 1 second of silence at 44.1 kHz
norm_rir = pf.Signal(imp_tot, fs) # don't use the pf.dsp.normalize function on an empty signal, as it returns NaN values.
else:
rir = pf.Signal(imp_tot, fs)
# Normalise the rir. Some methods return pressure values that are too high, which causes issues when writing to wav.
norm_rir = pf.dsp.normalize(rir)

pf.io.write_audio(norm_rir, rir_wav_file_name)
logger.info(f"Impulse response shape: {imp_tot.shape}, sampling rate: {fs}")

# logs = container.logs().decode("utf-8")
# logger.info(f"{simulation_method} container FULL logs:\n{logs}")

if os.path.exists(cancel_flag_path):
logger.info("Cancelled: do not save to xlsx")
logger.info("Cancelled: Not saving to xlsx")
else:
logger.info("Saving to xlsx...")

# save the simulation result json to xlsx
if not ExportHelper.parse_json_file_to_xlsx_file(
json_path, json_path.replace(".json", ".xlsx")
):
logger.error("Error saving the result to xlsx")
raise "Error saving the result to xlsx"

# db - save the xlsx file path
export = Export(
name=Path(json_path).name.replace(".json", ".xlsx"),
simulationId=simulation.id,
)
session.add(export)

# auralization: generate impulse response wav file
# TODO: fix DG method such that this auralization works,
# the idea is to have one shared pipeline across all
# methods.
match simulation_method:
case "DG":
imp_tot, fs = auralization_calculation_DG(
None,
json_path.replace(".json", "_pressure.csv"),
json_path.replace(".json", ".wav"),
)
# this should be the only thing getting executed
case _:
imp_tot, fs = auralization_calculation(
None,
json_path.replace(".json", "_pressure.csv"),
json_path.replace(".json", ".wav"),
)


# auralization: save the impulse response to xlsx
if not ExportHelper.write_data_to_xlsx_file(
json_path.replace(".json", ".xlsx"),
CustomExportParametersConfig.impulse_response,
{f"{fs}Hz": imp_tot},
):
logger.error(
"Error saving the impulse response to xlsx"
try:
logger.info("Saving to xlsx...")

# save the simulation result json to xlsx
if not ExportHelper.parse_json_file_to_xlsx_file(
json_path, json_path.replace(".json", ".xlsx")
):
logger.error("Error saving the result to xlsx")
raise RuntimeError("Error saving the result to xlsx")

Comment thread
mberz marked this conversation as resolved.
# db - save the xlsx file path
export = Export(
name=Path(json_path).name.replace(".json", ".xlsx"),
simulationId=simulation.id,
)
raise "Error saving the impulse response to xlsx"

session.add(export)

# auralization: save the impulse response to xlsx
if not ExportHelper.write_data_to_xlsx_file(
json_path.replace(".json", ".xlsx"),
CustomExportParametersConfig.impulse_response,
{f"{fs}Hz": imp_tot},
):
logger.error(
"Error saving the impulse response to xlsx"
)
raise RuntimeError("Error saving the impulse response to xlsx")
except Exception as ex:
logger.error(f"Error during saving results: {ex}")
raise RuntimeError(f"Error during saving results: {ex}")

result_container = {}
if json_path is not None:
Expand Down
7 changes: 0 additions & 7 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
"myst_parser",
"sphinx_design",
"sphinx_copybutton",
"sphinx_gallery.gen_gallery",
]
source_suffix = [".rst", ".md"]

Expand Down Expand Up @@ -59,9 +58,3 @@
html_context = {
"default_mode": "light"
}

sphinx_gallery_conf = {
"examples_dirs": "../../simulation-backend/examples", # path to your example scripts
"gallery_dirs": "auto_examples", # path to where to save gallery generated output
"image_scrapers": ("matplotlib",),
}
18 changes: 14 additions & 4 deletions docs/source/includes/api_documentation.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
API Documentation
=================

Services
--------

.. toctree::
:maxdepth: 1
:caption: Implemented Interfaces:

api_documentation/MyNewMethodinterface
api_documentation/DEinterface
api_documentation/DGinterface
api_documentation/executors.rst
api_documentation/discovery_service.rst
api_documentation/export_service.rst
api_documentation/file_service.rst
api_documentation/geometry_service.rst
api_documentation/material_service.rst
api_documentation/mesh_service.rst
api_documentation/model_service.rst
api_documentation/project_service.rst
api_documentation/setting_service.rst
api_documentation/simulation_service.rst
7 changes: 0 additions & 7 deletions docs/source/includes/api_documentation/DEinterface.rst

This file was deleted.

7 changes: 0 additions & 7 deletions docs/source/includes/api_documentation/DGinterface.rst

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Auralization Service
====================

.. automodule:: app.services.auralization_service
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/source/includes/api_documentation/discovery_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Discovery Service
=================

.. automodule:: app.services.discovery_service
:members:
:undoc-members:
:show-inheritance:
12 changes: 12 additions & 0 deletions docs/source/includes/api_documentation/executors.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Executors
=========

.. automodule:: app.services.executors.local_executor
:members:
:undoc-members:
:show-inheritance:

.. automodule:: app.services.executors.cloud_executor
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/source/includes/api_documentation/export_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Export Service
==============

.. automodule:: app.services.export_service
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/source/includes/api_documentation/file_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
File Service
============

.. automodule:: app.services.file_service
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/source/includes/api_documentation/geometry_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Geometry Service
================

.. automodule:: app.services.geometry_service
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/source/includes/api_documentation/material_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Material Service
================

.. automodule:: app.services.material_service
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/source/includes/api_documentation/mesh_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Mesh Service
============

.. automodule:: app.services.mesh_service
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/source/includes/api_documentation/model_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Model Service
=============

.. automodule:: app.services.model_service
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/source/includes/api_documentation/project_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Project Service
===============

.. automodule:: app.services.project_service
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/source/includes/api_documentation/setting_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Setting Service
===============

.. automodule:: app.services.setting_service
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/source/includes/api_documentation/simulation_service.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Simulation Service
==================

.. automodule:: app.services.simulation_service
:members:
:undoc-members:
:show-inheritance:
Loading
Loading