Skip to content

Commit

Permalink
add ensure seq, jit sound estimator optimisation, minor fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
MangaBoba committed Nov 24, 2023
1 parent 7bf80fc commit 17fc0a1
Show file tree
Hide file tree
Showing 15 changed files with 138 additions and 397 deletions.
132 changes: 0 additions & 132 deletions cases/sound_waves/configuration/config.py

This file was deleted.

134 changes: 28 additions & 106 deletions cases/sound_waves/configuration/config_parallel.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
from copy import deepcopy
from functools import partial
from pathlib import Path

import numpy as np

from cases.sound_waves.microphone_points import Microphone
from gefest.core.geometry.datastructs.point import Point
from gefest.core.geometry.datastructs.polygon import Polygon
from gefest.tools.tuners.utils import percent_edge_variance
from gefest.tools.utils import poly_from_comsol_txt
from gefest.core.configs.optimization_params import OptimizationParams
from gefest.core.configs.tuner_params import TunerParams
from gefest.core.geometry.datastructs.structure import Structure
Expand All @@ -19,109 +14,42 @@
SoundSimulator,
generate_map,
)

# # # Metrics # # #
DAMPING = 1 - 0.001
CA2 = 0.5
INITIAL_P = 200
MAX_PRESSURE = INITIAL_P / 2
MIN_PRESSURE = -INITIAL_P / 2

import numpy as np
from gefest.tools.tuners.utils import percent_edge_variance
from gefest.tools.utils import poly_from_comsol_txt


import itertools
from numpy.core.umath import pi
class SoundFieldFitness(Objective):
"""Evaluates sound pressure level difference with reference."""

def __init__(self, domain, estimator, best_spl, duration):
def __init__(self, domain, estimator, path_best_struct=None, micro_slice=-1):
super().__init__(domain, estimator)
self.path_best_struct = path_best_struct
self.micro_slice = micro_slice
if path_best_struct is None:
print('please, set up the best spl matrix into configuration')
print('the best structure will be generated randomly')
rnd_structure = get_random_structure(domain)
best_spl = generate_map(domain, rnd_structure)
else:
best_structure = poly_from_comsol_txt(path_best_struct)
best_spl = self.estimator(best_structure)
best_spl = np.nan_to_num(best_spl, nan=0, neginf=0, posinf=0)
micro = Microphone(matrix=best_spl).array()
best_spl = np.concatenate(micro[micro_slice])

self.best_spl = best_spl
self.omega = 3 / (2 * pi)
self.iteration = 0
self.map_size = (round(1.2 * domain.max_y), round(1.2 * domain.max_x))
self.size_y, self.size_x = self.map_size
self.duration = duration

# Source position is the center of the map
self.s_y = self.size_y // 2
self.s_x = self.size_x // 2

def update_velocity(self, velocities, pressure, obstacle_map):
"""Update the velocity field based on Komatsuzaki's transition rules."""
V = velocities
P = pressure
for i, j in itertools.product(range(self.size_y), range(self.size_x)):
if obstacle_map[i, j] == 1:
V[i, j, 0:4] = 0.0
continue

V[i, j, 0] = V[i, j, 0] + P[i, j] - P[i - 1, j] if i > 0 else P[i, j]
V[i, j, 1] = V[i, j, 1] + P[i, j] - P[i, j + 1] if j < self.size_x - 1 else P[i, j]
V[i, j, 2] = V[i, j, 2] + P[i, j] - P[i + 1, j] if i < self.size_y - 1 else P[i, j]
V[i, j, 3] = V[i, j, 3] + P[i, j] - P[i, j - 1] if j > 0 else P[i, j]

return V

def step(self, velocities, pressure, obstacle_map):
"""Perform a simulation step, upadting the wind an pressure fields."""
pressure[self.s_y, self.s_x] = INITIAL_P * np.sin(self.omega * self.iteration)
velocities = self.update_velocity(velocities, pressure, obstacle_map)
pressure = self.update_perssure(pressure, velocities)
self.iteration += 1
return velocities, pressure

def update_perssure(self, pressure, velocities):
"""Update the pressure field based on Komatsuzaki's transition rules."""
pressure -= CA2 * DAMPING * np.sum(velocities, axis=2)
return pressure

def spl(self, pressure_hist, integration_interval=60):
"""Computes the sound pressure level map.
https://en.wikipedia.org/wiki/Sound_pressure#Sound_pressure_level
Args:
integration_interval (int): interval over which the rms pressure
is computed, starting from the last
simulation iteration backwards.
Returns:
spl (np.array): map of sound pressure level (dB).
"""
p0 = 20 * 10e-6 # Pa
if integration_interval > pressure_hist.shape[0]:
integration_interval = pressure_hist.shape[0]

rms_p = np.sqrt(np.mean(np.square(pressure_hist[-integration_interval:-1]), axis=0))

rms_p[rms_p == 0.0] = 0.000000001
matrix_db = 20 * np.log10(rms_p / p0)
return matrix_db

def _evaluate(self, ind: Structure):
self.iteration = 0
obstacle_map = np.zeros((self.size_y, self.size_x))
obstacle_map = generate_map(self.domain, ind)
pressure = np.zeros((self.size_y, self.size_x))
pressure_hist = np.zeros((self.duration, self.size_y, self.size_x))
velocities = np.zeros((self.size_y, self.size_x, 4))

for iteration in range(self.duration):
pressure_hist[iteration] = deepcopy(pressure)
velocities, pressure = self.step(velocities, pressure, obstacle_map)

spl = self.spl(pressure_hist)

spl = self.estimator(ind)
current_spl = np.nan_to_num(spl, nan=0, neginf=0, posinf=0)
micro = Microphone(matrix=current_spl).array()
current_spl = np.concatenate(micro[-1])
l_f = np.sum(np.abs(deepcopy(self.best_spl) - current_spl))
current_spl = np.concatenate(micro[self.micro_slice])
l_f = np.sum(np.abs(self.best_spl - current_spl))
return l_f / len(current_spl)


# # # Precompute domain arguments # # #
# # # domain pre-computation

pass

Expand Down Expand Up @@ -150,20 +78,14 @@ def _evaluate(self, ind: Structure):

tuner_cfg = TunerParams(
tuner_type='sequential',
n_steps_tune=1000,
n_steps_tune=10,
hyperopt_dist='normal',
verbose=True,
variacne_generator=partial(percent_edge_variance, percent=0.5),
variacne_generator=partial(percent_edge_variance, percent=0.2),
timeout_minutes=30,
)


best_structure = poly_from_comsol_txt(str(Path(__file__).parent) + '\\figures\\bottom_square.txt')
best_spl = SoundSimulator(domain_cfg, 200, None)(best_structure)
best_spl = np.nan_to_num(best_spl, nan=0, neginf=0, posinf=0)
micro = Microphone(matrix=best_spl).array()
best_spl = np.concatenate(micro[-1])

opt_params = OptimizationParams(
optimizer='gefest_ga',
domain=domain_cfg,
Expand All @@ -172,7 +94,7 @@ def _evaluate(self, ind: Structure):
pop_size=100,
postprocess_attempts=3,
mutation_prob=0.9,
crossover_prob=0.7,
crossover_prob=0.6,
mutations=[
'rotate_poly',
'resize_poly',
Expand All @@ -182,7 +104,7 @@ def _evaluate(self, ind: Structure):
'drop_poly',
'pos_change_point',
],
selector='roulette_selection',
selector='tournament_selection',
mutation_each_prob=[0.125, 0.125, 0.25, 0.25, 0.0, 0.0, 0.25],
crossovers=[
'polygon_level',
Expand All @@ -208,9 +130,9 @@ def _evaluate(self, ind: Structure):
objectives=[
SoundFieldFitness(
domain_cfg,
None,
best_spl,
200
SoundSimulator(domain_cfg, 200),
str(Path(__file__).parent) + '\\figures\\bottom_square.txt',
-1,
),
],
)
4 changes: 2 additions & 2 deletions docs/source/tutorials/tuning.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ Here we will take a closer look at several ``TunerParams`` attributes which may

.. code-block:: python
from gefest.tools.tuners.utils import verage_edge_variance
from gefest.tools.tuners.utils import percent_edge_variance
tuner_cfg = TunerParams(
tuner_type='optuna',
n_steps_tune=10,
hyperopt_dist='uniform',
variance_generator=verage_edge_variance,
variance_generator=percent_edge_variance,
verbose=True,
timeout_minutes=60,
)
Expand Down
Loading

0 comments on commit 17fc0a1

Please sign in to comment.