Custom Low-Frequency Solvers
HybridSolver delegates low frequencies to a HybridBackend and uses MSGB
for high frequencies. A backend provides one or more callables with this
signature:
No Beamax base class is required. Implement at least one of forward,
time_reversal, or adjoint; calling an omitted operation raises
NotImplementedError.
Data flow
HybridSolversplits the input into LF and HF components.- With
downsample=True, it moves the LF component and sensor mask to a component grid. - It solves the HF component and passes the LF component plus a
HybridContextto the backend. - It applies LF windowing/interpolation and combines both results on the target shape.
Return a result on ctx.component_domain. HybridSolver handles interpolation
when downsample=True; otherwise the backend owns the full-resolution result.
Minimal adapter
A typical adapter is:
def lf_forward(component, ctx):
return my_wave_solver.forward(
component,
domain=ctx.component_domain,
sensors=ctx.component_sensor_mask,
ts=ctx.ts,
)
hybrid = HybridSolver(
hf_solver=msgb,
lf_backend=HybridBackend(forward=lf_forward, name="my LF solver"),
cutoff_freq=0.35,
downsample=False,
)
This configuration supports only hybrid.forward(...).
Existing beamax-style solvers
Wrap solvers with beamax-style arguments using
HybridBackend.from_beamax_solver:
from beamax.solvers import HybridBackend, HybridSolver, KWaveSolver, MSGBSolver
kwave = KWaveSolver(...)
msgb = MSGBSolver(...)
hybrid = HybridSolver(
hf_solver=msgb,
lf_backend=HybridBackend.from_beamax_solver(kwave),
box_corners=...,
)
It maps the context to the corresponding solver arguments for forward,
time_reversal, and adjoint. Use an explicit adapter for custom source
layouts, boundary weights, or extra arguments.
Shapes
component_array is the split LF component. With downsample=True, it lives
on ctx.component_domain; otherwise that domain is the original grid.
forward should return sensor data with time on axis 0. ctx.ts may include
time-extension samples; HybridSolver removes the extension after merging.
time_reversal and adjoint should return an image on
ctx.component_domain.N. With downsampling, HybridSolver interpolates it to
ctx.target_shape.
Use downsample=False when the LF solver owns its grid, uses off-grid or sparse
sensors, or cannot consume the interpolated mask. The backend then receives
full-resolution fields and masks, and its result is not interpolated.
j-Wave
j-Wave is optional and not a beamax dependency. Its JAX and JaxDF constraints
may differ from beamax's, so check resolver compatibility before combining them.
Convert dense masks to j-Wave index arrays inside the adapter. Use
downsample=False for off-grid or sparse sensors.
References: