RaySolver

Model AcousticRayTracers.RaySolver
Description 2½D acoustic Gaussian beam tracer
Language Julia
Advantages Differentiable (forward mode)
Limitations Tell us and we will fix them!
Differentiability ForwardDiff
RaySolver(env; kwargs...)

Julia implementation of a ray/Gaussian beam propagation model. The model supports complex environments, but retains differentiability.

Supported keyword arguments:

  • nbeams: number of beams to use (default: 0, auto)
  • min_angle: minimum beam angle (default: -80°)
  • max_angle: maximum beam angle (default: 80°)
  • ds: nominal spacing between ray points (default: 1/10 water depth)
  • atol: absolute position tolerance (default: 0.0001 m)
  • rugosity: TODO (default: 1.5)
  • min_amplitude: minimum ray amplitude to track (default: 1e-5)
  • solver: differential equation solver (default: nothing, auto)
  • solver_tol: solver tolerance (default: 1e-4)
  • backscatter: continue tracing rays that turn back toward the source (default: false)
  • rmin: left edge of modeling domain in m, ≤ 0 (default: 0; only meaningful with backscatter)
  • rmax: right edge of modeling domain in m (default: 0, auto = query range)

If the environment contains scatterers (env.scatterers), rays reflect off them using the scatterer’s boundary condition. With backscatter enabled, rays are traced until they exit the modeling domain r ∈ [rmin, rmax] or become too weak (min_amplitude, including absorption); backscattered arrivals are reported with |arrival angle| > π/2. Features outside the modeling domain are invisible; set rmax beyond the query range to capture echoes from behind the receivers. If rmin < 0, a second fan of rays with the same elevation angles is launched in the -x direction, so that features to the left of the transmitter can also produce echoes (such arrivals have |launch angle| > π/2).

RaySolver is a differentiable 2½D Gaussian beam tracer similar to Bellhop, but fully written in Julia to be compatible with automatic differentiation (AD) tools such as ForwardDiff. Its implementation is largely based on the description in:

Example

using UnderwaterAcoustics
using AcousticRayTracers
using Plots

env = UnderwaterEnvironment(
  bathymetry = SampledField([200, 150]; x=[0, 1000], interp=Linear()),
  soundspeed = SampledField([1500, 1480, 1495, 1510, 1520]; z=0:-50:-200, interp=CubicSpline()),
  seabed = SandyClay
)
pm = RaySolver(env)

tx = AcousticSource(0, -50, 300)
rx = AcousticReceiver(1000, -100)
rays = arrivals(pm, tx, rx)

plot(env; xlims=(-10, 1010))
plot!(tx)
plot!(rx)
plot!(rays)
rxs = AcousticReceiverGrid2D(1:1000, -200:0)
x = transmission_loss(pm, tx, rxs; mode=:coherent)

plot(rxs, x; crange=70)
plot!(env; xlims=(0,1000), linewidth=3)

Backscatter

By default, RaySolver terminates rays that turn around and head back toward the source. Enabling the backscatter option continues tracing such rays until they exit the modeling domain (\(\texttt{rmin} ≤ x ≤ \texttt{rmax}\)) or become too weak to matter (min_amplitude). This allows the model to predict echoes from steep bathymetric features. Backscattered eigenrays are reported with arrival angles \(|θᵣ| > 90°\), and contribute to arrivals, acoustic fields and impulse responses.

If rmax is not specified, the modeling domain extends to the query range (the receiver range, or the far edge of a receiver grid) — the same domain as without backscatter. Anything beyond the domain is invisible to the model, so echoes from features behind the receivers require an explicit larger rmax (as in the example below, where the slope lies beyond the receiver). Setting rmin < 0 extends the domain to the left of the transmitter; a second fan of rays with the same elevation angles is then automatically launched in the \(-x\) direction, so that features to the left of the transmitter can also produce echoes (such arrivals have launch angles \(|θₛ| > 90°\)).

To illustrate, we place a transmitter and a receiver in a 200 m deep channel that ends in a steep rocky slope rising to 10 m depth. Rays travel past the receiver, reverse off the slope (via slope and surface bounce combinations), and return to the receiver from behind. We plot the strongest 3 forward and strongest 3 backscattered eigenrays:

env = UnderwaterEnvironment(
  bathymetry = SampledField([200, 200, 10]; x=[0, 800, 1000], interp=Linear()),
  soundspeed = 1500,
  seabed = Rock
)
pm = RaySolver(env; backscatter=true, rmax=1000)

tx = AcousticSource(0, -50, 300)
rx = AcousticReceiver(400, -100)
rays = arrivals(pm, tx, rx)

fwd = filter(a -> abs(a.θᵣ)  π/2, rays)        # forward eigenrays
echoes = filter(a -> abs(a.θᵣ) > π/2, rays)     # backscattered eigenrays
strongest(a, n) = sort(a; by = x -> abs(x.ϕ), rev=true)[1:min(n, length(a))]

plot(env; xlims=(-10, 1010))
plot!(tx)
plot!(rx)
plot!(strongest(fwd, 3))
plot!(strongest(echoes, 3))

Scatterers (experimental)

RaySolver has experimental support for discrete scatterers in the water column, described in the environment with the scatterers field (see Scatterer). Rays reflect specularly off the scatterer boundary: the amplitude is given by the scatterer’s acoustic boundary condition via the standard reflection coefficient at the local tangent plane, and the Gaussian beam spreading is corrected for the curvature of the surface. Scatterer geometry may be differentiated through, i.e., gradients of acoustic quantities with respect to scatterer position and size are supported.

Scatterers are usually used together with backscatter=true, so that target echoes propagate back toward the source. Here, a small rigid ellipse on the transmitter–receiver line blocks the direct path, while a larger rigid ellipse, shallower and beyond the receiver, is rotated so that its face reflects the transmitter’s rays down to the receiver:

env = UnderwaterEnvironment(
  bathymetry = 200,
  soundspeed = 1500,
  seabed = SandyClay,
  scatterers = (
    Scatterer(Ellipse(125, -100, 8, 3; θ=90°), RigidBoundary),   # blocks the direct path
    Scatterer(Ellipse(450, -60, 10, 4; θ=-82°), RigidBoundary)   # reflects toward the receiver
  )
)
pm = RaySolver(env; backscatter=true, rmax=600, nbeams=2500)

tx = AcousticSource(0, -100, 1000)
rx = AcousticReceiver(250, -100)
rays = arrivals(pm, tx, rx)

fwd = filter(a -> abs(a.θᵣ)  π/2, rays)
echoes = filter(a -> abs(a.θᵣ) > π/2, rays)

plot(env; xlims=(-10, 610))
plot!(tx)
plot!(rx)
plot!(strongest(fwd, 3))
plot!(strongest(echoes, 3))

There is no direct eigenray — every forward path detours around the blocking scatterer — and the strongest echoes arrive from the tilted reflector behind and above the receiver. The transmission loss field shows the geometric shadows cast by both targets, and the interference of the backscattered field with the outgoing field:

rxs = AcousticReceiverGrid2D(1:600, -200:0)
x = transmission_loss(pm, tx, rxs; mode=:coherent)

plot(rxs, x; crange=70)
plot!(env; xlims=(0,600), linewidth=3)

Limitations

The scatterer implementation is experimental, and has the following limitations:

  • Tangent-plane (Kirchhoff) coupling: the reflection is computed with the plane-wave reflection coefficient at the local tangent plane. This is valid when the scatterer is large compared to a wavelength (\(ka ≫ 1\)) and away from grazing incidence. There is no diffraction or creeping-wave contribution, so shadow edges are geometric (softened only by the Gaussian beam width). Small or low-frequency targets (\(ka ≲ 1\)) are not modeled correctly and need a target-strength model instead.
  • Grazing incidence: the beam-spreading curvature correction diverges at grazing incidence, and is skipped for grazing angles below \(\sin θ_g = 10^{-3}\). The correction is verified against an analytic (mirror equation) benchmark from normal incidence down to \(\sin θ_g ≈ 0.93\); between these it follows the standard analytic form but is not independently benchmarked.
  • 2½D semantics: a 2D scatterer with cylindrical out-of-plane spreading models a target extended in the cross-range (\(y\)) direction, not a compact 3D body — a real sphere’s target strength is not reproduced.
  • Eigenray search resolution: echoes off small scatterers subtend narrow launch-angle windows, and the default nbeams heuristic may miss them. Increase nbeams (a few thousand) when scatterer echoes matter. Transmission loss fields computed over a receiver grid do not suffer from this.
  • Modeling domain: rays exiting the domain (\(x < \texttt{rmin}\) or \(x > \texttt{rmax}\)) are assumed to never return, so anything reflective outside the domain is invisible to the model. Since rmax defaults to the query range and rmin to 0, features behind the receivers or to the left of the transmitter are only seen if the domain is explicitly extended to include them.

Notes

The RaySolver propagation model requires that the transmitter is located at \((x=0, y=0)\) and all receivers are located in the right half-plane (i.e., \(x>0\) and \(y=0\)). This limitation can be worked around by wrapping the model with Reframe2D, which automatically transforms 2D scenarios specified in world coordinates into the coordinate system required by the model (see the quickstart guide for an example).