Metadiffusers: deep-subwavelength Schroeder diffusers - #397
Conversation
A new materials module models the slotted panels of Jimenez, Cox, Romero-Garcia and Groby (Sci. Rep. 7:5389, 2017): thin slits loaded by Helmholtz resonators whose slow sound pulls the quarter-wavelength condition of each well into the deep-subwavelength regime, so a centimetres-thick panel reproduces the reflection-phase profile of a Schroeder diffuser tens of centimetres deep, and critically coupled slits provide the perfectly absorbing state of ternary sequences. The per-well chain reuses the slow-sound absorber transfer matrix, extended with the paper's two-dimensional resonator model: slit-geometry visco-thermal effective parameters for necks and cavities and the 2-D end-correction fits (0.41 w_n polynomials), selected by a new resonator_geometry switch that keeps the square-duct model as default elsewhere. metadiffuser_reflection returns the per-well complex R_n(f), and metadiffuser_polar_response / metadiffuser_diffusion_spectrum reduce it through the bare Fraunhofer far field of the paper (no obliquity factor) to the ISO 17497-2 directional and normalized coefficients. The tests pin the implementation to the published designs: the first slit of the quadratic-residue panel reaches critical coupling at the printed 2270 Hz within 1.6 %, its reflection matches the target QRD at the 2 kHz evaluation to under 4 degrees per well, the ternary perfect absorber peaks at alpha = 0.999 at 502 Hz, the primitive-root panel shows its sharp slit resonance at 1505 Hz and a -19 dB specular notch, and the diffusion coefficients of the supplementary land inside soft bounds. Necks wider than their slit fall outside the fitted domain of the Dubos correction and now raise a warning (the broadband Table 4 design does this by construction, so only its mid-band diffusion is pinned). The surface-scattering guide gains a metadiffuser section with the published five-slit panel as a runnable example, a to-scale panel drawing (MetadiffuserResult.plot_geometry) and a polar overlay showing the 2 cm panel scattering like the 27.4 cm QRD it mimics.
… fields The clip compares a flat rigid control slab, the 27 cm QRD and the 2 cm metadiffuser under the same tapered 2 kHz wavefront, all in a free-field box (sponges on the four sides; the lateral cosine taper keeps the incident front off the side sponges, so it stays plane and the free-field reference subtracts exactly). A unit-cell convergence check against the transfer-matrix phase fixed the mesh at 0.25 mm, where the reflection phase is converged to under 2 degrees; the fields run on the .env GPU host through the fdtd_gpu runner when it answers, with a three-worker CPU pool as the fallback.
|
Warning Review limit reached
Next review available in: 6 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR adds resonator-loaded slit-panel metadiffuser modeling, selectable resonator geometries, reflection/polar/diffusion APIs, plotting, generated figures and animations, public exports, tests, and English/Spanish documentation. ChangesMetadiffuser feature
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant MetadiffuserAPI
participant SlitAbsorber
participant PolarModel
participant DiffusionModel
Caller->>MetadiffuserAPI: submit wells and frequencies
MetadiffuserAPI->>SlitAbsorber: compute per-well reflection
Caller->>MetadiffuserAPI: request polar response
MetadiffuserAPI->>PolarModel: pass reflection sequence
Caller->>MetadiffuserAPI: request diffusion spectrum
MetadiffuserAPI->>DiffusionModel: normalize directional diffusion
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Reviewer's GuideAdds a full metadiffuser modeling pipeline (materials API, plotting, docs, tests, and example figures/animations) plus an optional remote GPU AV1 encoding path for animations, enabling comparison between a deep Schroeder QRD and a thin metadiffuser panel in both prediction and 2D FDTD simulation. Sequence diagram for the new GPU AV1 animation encoding pathsequenceDiagram
participant Caller as generate_*_figure
participant Save as _save_animation
participant GPU as _gpu_encode_target
participant Wrap as _write_gpu_ffmpeg_wrapper
participant FFM as FFMpegWriter
Caller->>Save: _save_animation(anim, fig, output_dir, stem)
Save->>GPU: _gpu_encode_target()
GPU-->>Save: gpu_config or None
alt gpu_config is not None
Save->>Wrap: _write_gpu_ffmpeg_wrapper(target, image, workdir)
Wrap-->>Save: wrapper_path
Save->>FFM: FFMpegWriter(codec="av1_nvenc", extra_args=_av1_nvenc_extra_args())
Save->>Save: anim.save(webm, writer, ffmpeg_path=wrapper)
Note over Save: On success: saved = True
Save->>Save: os.remove(wrapper_path)
else gpu_config is None or GPU encode fails
Save->>FFM: FFMpegWriter(codec="libvpx-vp9", extra_args=_vp9_extra_args())
Save->>Save: anim.save(webm, writer)
end
Save->>Save: _extract_poster(webm)
Save-->>Caller: WebM (AV1 or VP9) saved
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/surface-scattering.md`:
- Around line 862-869: Update the citation in the surface-scattering
documentation to use the accented author names “Jiménez” and “Romero-García,”
matching the corresponding mirrored documentation while preserving the rest of
the reference unchanged.
In `@scripts/generate_graphs.py`:
- Around line 14794-14880: Reduce peak memory in _metadiffuser_fields by storing
the clipped trail_db output in a compact representation such as float16 or uint8
while preserving the fixed −30..0 dB range, and replace the GPU branch’s history
list with a preallocated array filled from the running envelope instead of
appending copies. Keep the returned trail values and downstream behavior
unchanged.
- Line 14577: In animate_fdtd_diffusion, change the panel loop from range(3)
back to range(2) so it matches the two-column gridspec and the two-entry titles,
beams, polys, and diffusion fields. Leave the separate range(3) loop in
animate_fdtd_metadiffuser unchanged.
- Around line 14884-14887: Update the docstring near the graph-generation code
to state the actual 0.25 mm mesh resolution and describe the result as
qualitative scattered-fan similarity only; remove the unsupported claim about
near-identical diffusion coefficients, since quantitative comparison is handled
by the companion polar figure.
- Around line 14876-14879: Guard the ref calculation in the trail processing
flow so a zero maximum from trail[:, trail.shape[1] // 3:] is replaced with a
safe nonzero fallback before computing trail_db. Preserve the existing
logarithmic conversion and clipping behavior while ensuring no NaN values reach
imshow when the envelope window is empty.
- Around line 7961-7967: Define a single module-level constant for the five
Table-1 `(h, ln, lc, wn, wc)` rows, then update the row definition in the
analytic polar figure and `_metadiffuser_panel_mask` to reuse that constant.
Remove both duplicated inline lists while preserving their existing ordering and
values.
In `@src/phonometry/_plot/geometry.py`:
- Around line 1097-1102: Update the public docstring for the slotted-panel
geometry near the side-cut renderer to match the plotted orientation: describe
the face at the top, wells extending downward in depth, and repeated wells
arranged horizontally, while preserving the existing descriptions of well
height, lattice spacing, rigid strips, and back wall.
In `@src/phonometry/materials/metadiffuser.py`:
- Around line 196-207: Update the public docstrings for metadiffuser_reflection
(src/phonometry/materials/metadiffuser.py:196-207), metadiffuser_polar_response
(src/phonometry/materials/metadiffuser.py:267-283), and
metadiffuser_diffusion_spectrum
(src/phonometry/materials/metadiffuser.py:333-346) to document the
resonator_geometry parameter, including its allowed "slit" and "square" values
and default. Apply the same parameter description at all three sites so
generated API parameter tables include it.
- Around line 139-143: Update MetadiffuserResult.plot_geometry() to import and
call the exported plot_metadiffuser_panel_geometry renderer instead of
plot_metadiffuser_geometry, passing the retained wells, depth, and period values
along with self, ax, language, and existing kwargs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 70256432-aa14-4dba-9d3e-db28d841a630
⛔ Files ignored due to path filters (19)
.github/images/anim_fdtd_metadiffuser.gifis excluded by!**/*.gif.github/images/anim_fdtd_metadiffuser.webmis excluded by!**/*.webm.github/images/anim_fdtd_metadiffuser_dark.gifis excluded by!**/*.gif.github/images/anim_fdtd_metadiffuser_dark.webmis excluded by!**/*.webm.github/images/anim_fdtd_metadiffuser_dark_poster.jpgis excluded by!**/*.jpg.github/images/anim_fdtd_metadiffuser_es.webmis excluded by!**/*.webm.github/images/anim_fdtd_metadiffuser_es_dark.webmis excluded by!**/*.webm.github/images/anim_fdtd_metadiffuser_es_dark_poster.jpgis excluded by!**/*.jpg.github/images/anim_fdtd_metadiffuser_es_poster.jpgis excluded by!**/*.jpg.github/images/anim_fdtd_metadiffuser_poster.jpgis excluded by!**/*.jpg.github/images/metadiffuser_geometry.svgis excluded by!**/*.svg.github/images/metadiffuser_geometry_dark.svgis excluded by!**/*.svg.github/images/metadiffuser_geometry_es.svgis excluded by!**/*.svg.github/images/metadiffuser_geometry_es_dark.svgis excluded by!**/*.svg.github/images/metadiffuser_polar.svgis excluded by!**/*.svg.github/images/metadiffuser_polar_dark.svgis excluded by!**/*.svg.github/images/metadiffuser_polar_es.svgis excluded by!**/*.svg.github/images/metadiffuser_polar_es_dark.svgis excluded by!**/*.svgsite/src/generated/api-sidebar.mjsis excluded by!**/generated/**
📒 Files selected for processing (16)
docs/api-reference.mddocs/surface-scattering.mdscripts/api_taxonomy.pyscripts/generate_graphs.pysite/src/content/docs/es/guides/surface-scattering.mdxsite/src/content/docs/guides/surface-scattering.mdxsite/src/content/docs/reference/api/index.mdsite/src/content/docs/reference/api/materials/metadiffuser.mdsite/src/content/docs/reference/api/materials/slow-sound-absorber.mdsrc/phonometry/__init__.pysrc/phonometry/_plot/geometry.pysrc/phonometry/_plot/materials.pysrc/phonometry/materials/__init__.pysrc/phonometry/materials/metadiffuser.pysrc/phonometry/materials/slow_sound_absorber.pytests/materials/test_metadiffuser.py
| from .._i18n import check_language | ||
| from .._plot.geometry import plot_metadiffuser_geometry | ||
|
|
||
| check_language(language) | ||
| return plot_metadiffuser_geometry(self, ax=ax, language=language, **kwargs) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Call the exported renderer with the retained geometry.
plot_metadiffuser_geometry is not the new renderer; plot_metadiffuser_panel_geometry requires wells, depth, and period. As written, every MetadiffuserResult.plot_geometry() call fails at import time.
Proposed fix
- from .._plot.geometry import plot_metadiffuser_geometry
+ from .._plot.geometry import plot_metadiffuser_panel_geometry
check_language(language)
- return plot_metadiffuser_geometry(self, ax=ax, language=language, **kwargs)
+ if self.wells is None or self.depth is None or self.period is None:
+ raise ValueError("The result does not retain panel geometry.")
+ return plot_metadiffuser_panel_geometry(
+ self.wells,
+ ax=ax,
+ depth=self.depth,
+ period=self.period,
+ language=language,
+ **kwargs,
+ )📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| from .._i18n import check_language | |
| from .._plot.geometry import plot_metadiffuser_geometry | |
| check_language(language) | |
| return plot_metadiffuser_geometry(self, ax=ax, language=language, **kwargs) | |
| from .._i18n import check_language | |
| from .._plot.geometry import plot_metadiffuser_panel_geometry | |
| check_language(language) | |
| if self.wells is None or self.depth is None or self.period is None: | |
| raise ValueError("The result does not retain panel geometry.") | |
| return plot_metadiffuser_panel_geometry( | |
| self.wells, | |
| ax=ax, | |
| depth=self.depth, | |
| period=self.period, | |
| language=language, | |
| **kwargs, | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/phonometry/materials/metadiffuser.py` around lines 139 - 143, Update
MetadiffuserResult.plot_geometry() to import and call the exported
plot_metadiffuser_panel_geometry renderer instead of plot_metadiffuser_geometry,
passing the retained wells, depth, and period values along with self, ax,
language, and existing kwargs.
|
@coderabbitai review |
✅ Action performedReview finished.
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #397 +/- ##
========================================
Coverage 96.80% 96.81%
========================================
Files 220 221 +1
Lines 31937 32120 +183
========================================
+ Hits 30918 31096 +178
- Misses 1019 1024 +5 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Numerical conformance report✅ 427/427 conformance checks pass across 53 domains and 278 standards - filters class 1 - weightings within IEC 61672-1 class 1. Each row pins a standard clause to its expected normative value and the value the library computes. Every section below is collapsible and stays collapsed while all of its rows pass; a section with any failing row opens automatically. ✅ Numerical validation - filters & weightings: class showcase (IEC 61260-1 · IEC 61672-1 · ISO 7196)IEC 61260-1:2014 class per filter architecture (order 6, one-third-octave, 100 Hz-10 kHz, fs = 48 kHz). For each architecture the table shows, at its binding band, the measured relative attenuation and the class-1 limit it must clear, so the number and the range it must sit in are both visible. A positive margin means the acceptance limits are met with that much room.
Only Butterworth (the library default) and Chebyshev-II are class-compliant architectures. Chebyshev-I and elliptic trade the mask for passband ripple, and Bessel for a maximally-flat group delay (soft rolloff); they cannot satisfy the IEC 61260-1 Class 1/2 attenuation mask by construction, so they are labelled By design - this is expected, not a failure or regression. Frequency-weighting conformance (A/C: IEC 61672-1 Table 3; G: ISO 7196 A.3). The max deviation from nominal is informational (it falls at a frequency extreme where the tolerance is widest and asymmetric); compliance is judged at the binding frequency - the one with the least headroom - where the deviation, the applicable tolerance band and the headroom are shown together.
✅ Filters & weightings: 100% (10/10)
✅ Levels & dosimetry: 100% (6/6)
✅ Room acoustics: 100% (12/12)
✅ Psychoacoustics: 100% (12/12)
✅ Speech transmission (IEC 60268-16): 100% (10/10)
✅ System measurement (Golay / Kirkeby / Mueller-Massarani): 100% (5/5)
✅ Intensity & sound power: 100% (6/6)
✅ Room & building acoustics: 100% (52/52)
✅ Building prediction & uncertainty: 100% (15/15)
✅ Outdoor propagation & occupational exposure: 100% (10/10)
✅ Materials: absorption, airflow & impedance: 100% (6/6)
✅ Scattering & diffusion (ISO 17497): 100% (14/14)
✅ In-situ road absorption (ISO 13472): 100% (3/3)
✅ Precision sound power (ISO 3745 / 9614-3): 100% (4/4)
✅ Human vibration (ISO 8041 / 2631 / 5349): 100% (15/15)
✅ Speech intelligibility (ANSI S3.5-1997): 100% (7/7)
✅ Objective intelligibility (STOI / ESTOI): 100% (3/3)
✅ Impulsive-sound prominence (NT ACOU 112): 100% (2/2)
✅ Impulsive-sound prominence (ISO/PAS 1996-3): 100% (2/2)
✅ Room noise (ANSI S12.2-2019): 100% (3/3)
✅ Hearing threshold (ISO 7029 / ISO 389-7): 100% (3/3)
✅ Measurement uncertainty (GUM / Supplement 1): 100% (7/7)
✅ Noise-induced hearing loss (ISO 1999): 100% (6/6)
✅ Multiple-shock whole-body vibration (ISO 2631-5): 100% (6/6)
✅ Sound absorption in enclosed spaces (EN 12354-6): 100% (2/2)
✅ Prominent discrete tones (ECMA-418-1): 100% (2/2)
✅ Tonal audibility (ISO/PAS 20065): 100% (11/11)
✅ Psychoacoustic annoyance & fluctuation strength (Fastl & Zwicker): 100% (3/3)
✅ Electroacoustics: distortion & frequency response: 100% (20/20)
✅ Calibrated spectral analysis (Bendat & Piersol): 100% (12/12)
✅ Multiple-input coherence (Bendat & Piersol): 100% (5/5)
✅ Time-frequency analysis (Bendat & Piersol): 100% (3/3)
✅ Correlation, time delay and envelope (B&P / Knapp & Carter): 100% (7/7)
✅ Cepstrum, liftering and envelope spectrum (Havelock / B&P): 100% (3/3)
✅ Time synchronous averaging (McFadden 1987): 100% (5/5)
✅ Data qualification and Rice statistics (Bendat & Piersol): 100% (8/8)
✅ Underwater acoustics (ISO 18405/17208/18406): 100% (6/6)
✅ Underwater sound propagation (transmission loss): 100% (15/15)
✅ Underwater numerical propagation (modes / rays / PE): 100% (4/4)
✅ Aircraft noise (ICAO Annex 16 / IEC 61265): 100% (15/15)
✅ Rotorcraft noise (ECAC Doc 32 / NORAH2): 100% (12/12)
✅ Wind-turbine noise (IEC 61400-11): 100% (3/3)
✅ Porous & multilayer absorbers (Mechel / Bies / Cox & D'Antonio): 100% (10/10)
✅ Slow-sound perfect absorbers (Jimenez et al. Appl. Sci. 2017): 100% (3/3)
✅ Program loudness (ITU-R BS.1770 / EBU R 128): 100% (8/8)
✅ 2D FDTD wave simulation (Attenborough & Van Renterghem 2021, Ch. 4): 100% (2/2)
✅ Swept-sine distortion & phase utilities (Farina / Novak): 100% (7/7)
✅ Spherical ground & barriers (Attenborough / Salomons / Bies): 100% (7/7)
✅ Panel & aperture sound insulation (Bies / Hopkins / Cremer): 100% (11/11)
✅ Bending-wave plate-junction transmission (Cremer / Craik / Hopkins): 100% (6/6)
✅ Atmospheric refraction (Salomons rays / GFPE): 100% (3/3)
✅ Electroacoustics: 100% (6/6)
✅ Industrial noise control: 100% (9/9)
Tests & coverage — 34506 tests, 0 failures (✅ all green)
Conformance harness: |
…smoke tests The three-column edit had also widened the panel loop of the original animate_fdtd_diffusion, which would crash its next render; the loop is back to two panels and the function is again identical to main. The Table-1 rows are hoisted into one shared constant, the trail reference is guarded against a silent zero, the GPU history is preallocated, the metadiffuser docstrings document resonator_geometry and the drawing orientation, the citation carries the accented author names, and the new plot renderers gained smoke tests in both languages (the SonarCloud coverage gap) together with the hoisted constructions and helper extractions the analysis asked for.
|
Review addressed in 2bdde65:
On "plot_metadiffuser_geometry is not the new renderer": not applied, it is a false positive. That name exists in src/phonometry/_plot/geometry.py as the retained-geometry wrapper (it validates wells/depth/period and delegates to plot_metadiffuser_panel_geometry), and the new smoke test exercises MetadiffuserResult.plot_geometry() end to end, including the ValueError path for hand-built results. |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
site/src/content/docs/reference/api/materials/metadiffuser.md (1)
37-53: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winDocument
resonator_geometryin all three parameter tables.The signatures expose
resonator_geometry, but the tables formetadiffuser_diffusion_spectrum,metadiffuser_polar_response, andmetadiffuser_reflectionomit it. Add the parameter description and regenerate this API page so users can discover the"slit"default and"square"alternative.Suggested additions
| `periods` | Number of repetitions `N_p` of the single period. | +| `resonator_geometry` | `"slit"` by default for two-dimensional resonators, or `"square"` for square-duct necks and cavities. |Apply the equivalent row to all three parameter tables.
Also applies to: 65-81, 88-104, 118-132, 139-153, 167-181
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@site/src/content/docs/reference/api/materials/metadiffuser.md` around lines 37 - 53, Update the parameter tables for metadiffuser_diffusion_spectrum, metadiffuser_polar_response, and metadiffuser_reflection to include resonator_geometry, documenting "slit" as the default and "square" as the alternative, then regenerate the API page so all three tables expose the parameter.scripts/generate_graphs.py (1)
12722-12735: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winPrevent configuration values from being evaluated by the local shell.
Line 12731 embeds
q_target,q_dir, andq_imageinside a local double-quoted command. A configured value containing$(...)is expanded by the wrapper beforesshstarts;shlex.quote()does not protect values in that context. This enables local command execution when GPU environment configuration is CI- or.env-controlled.Suggested direction
+target={q_target} +image={q_image} +workdir={q_dir} ... -ssh -o BatchMode=yes -- {q_target} \ - "mkdir -p {q_dir} && docker run --rm -i --gpus all \ - -v {q_dir}:/work {q_image}$quoted /work/$rid" -scp -q -- {q_target}:{q_dir}/"$rid" "$out" -ssh -o BatchMode=yes -- {q_target} "rm -f {q_dir}/$rid" +remote_cmd=$(printf 'mkdir -p %q && docker run --rm -i --gpus all -v %q:/work %q' \ + "$workdir" "$workdir" "$image") +remote_cmd+="$(printf ' %q' "${args[@]}")" +remote_cmd+=" $(printf '%q' "/work/$rid")" +ssh -o BatchMode=yes -- "$target" "$remote_cmd" +scp -q -- "$target:$workdir/$rid" "$out" +ssh -o BatchMode=yes -- "$target" "$(printf 'rm -f %q' "$workdir/$rid")"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/generate_graphs.py` around lines 12722 - 12735, Update the generated script around q_target, q_dir, and q_image so configuration values are passed to the remote shell as safely quoted arguments or environment values, rather than interpolated inside the local double-quoted ssh command. Ensure the remote command quotes those received values before using them, preventing local command substitution while preserving the docker, scp, and cleanup flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@scripts/generate_graphs.py`:
- Around line 12722-12735: Update the generated script around q_target, q_dir,
and q_image so configuration values are passed to the remote shell as safely
quoted arguments or environment values, rather than interpolated inside the
local double-quoted ssh command. Ensure the remote command quotes those received
values before using them, preventing local command substitution while preserving
the docker, scp, and cleanup flow.
In `@site/src/content/docs/reference/api/materials/metadiffuser.md`:
- Around line 37-53: Update the parameter tables for
metadiffuser_diffusion_spectrum, metadiffuser_polar_response, and
metadiffuser_reflection to include resonator_geometry, documenting "slit" as the
default and "square" as the alternative, then regenerate the API page so all
three tables expose the parameter.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 832060a8-cf92-4fe1-a8e4-6558a19aaede
📒 Files selected for processing (8)
docs/surface-scattering.mdscripts/generate_graphs.pysite/src/content/docs/reference/api/materials/metadiffuser.mdsonar-project.propertiessrc/phonometry/_plot/geometry.pysrc/phonometry/materials/metadiffuser.pysrc/phonometry/materials/slow_sound_absorber.pytests/materials/test_metadiffuser.py
|



The clip compares a flat rigid control slab, the 27 cm QRD and the 2 cm
metadiffuser under the same tapered 2 kHz wavefront, all in a free-field
box (sponges on the four sides; the lateral cosine taper keeps the
incident front off the side sponges, so it stays plane and the free-field
reference subtracts exactly). A unit-cell convergence check against the
transfer-matrix phase fixed the mesh at 0.25 mm, where the reflection
phase is converged to under 2 degrees; the fields run on the .env GPU
host through the fdtd_gpu runner when it answers, with a three-worker
CPU pool as the fallback.
A new materials module models the slotted panels of Jimenez, Cox,
Romero-Garcia and Groby (Sci. Rep. 7:5389, 2017): thin slits loaded by
Helmholtz resonators whose slow sound pulls the quarter-wavelength
condition of each well into the deep-subwavelength regime, so a
centimetres-thick panel reproduces the reflection-phase profile of a
Schroeder diffuser tens of centimetres deep, and critically coupled
slits provide the perfectly absorbing state of ternary sequences.
The per-well chain reuses the slow-sound absorber transfer matrix,
extended with the paper's two-dimensional resonator model: slit-geometry
visco-thermal effective parameters for necks and cavities and the 2-D
end-correction fits (0.41 w_n polynomials), selected by a new
resonator_geometry switch that keeps the square-duct model as default
elsewhere. metadiffuser_reflection returns the per-well complex R_n(f),
and metadiffuser_polar_response / metadiffuser_diffusion_spectrum reduce
it through the bare Fraunhofer far field of the paper (no obliquity
factor) to the ISO 17497-2 directional and normalized coefficients.
The tests pin the implementation to the published designs: the first
slit of the quadratic-residue panel reaches critical coupling at the
printed 2270 Hz within 1.6 %, its reflection matches the target QRD at
the 2 kHz evaluation to under 4 degrees per well, the ternary perfect
absorber peaks at alpha = 0.999 at 502 Hz, the primitive-root panel
shows its sharp slit resonance at 1505 Hz and a -19 dB specular notch,
and the diffusion coefficients of the supplementary land inside soft
bounds. Necks wider than their slit fall outside the fitted domain of
the Dubos correction and now raise a warning (the broadband Table 4
design does this by construction, so only its mid-band diffusion is
pinned).
The surface-scattering guide gains a metadiffuser section with the
published five-slit panel as a runnable example, a to-scale panel
drawing (MetadiffuserResult.plot_geometry) and a polar overlay showing
the 2 cm panel scattering like the 27.4 cm QRD it mimics.
Summary by CodeRabbit
New Features
Documentation
Tests