Source code for kwave.reconstruction.time_reversal
"""Time reversal reconstruction for photoacoustic imaging.This class handles time reversal reconstruction of initial pressure distributionfrom sensor data. It supports both 2D and 3D simulations and automaticallyapplies compensation for half-plane recording.Example: >>> tr = TimeReversal(kgrid, medium, sensor) >>> p0_recon = tr(kspaceFirstOrder2D, simulation_options, execution_options)"""fromtypingimportAny,Callable,Dictimportnumpyasnpfromkwave.kgridimportkWaveGridfromkwave.kmediumimportkWaveMediumfromkwave.ksensorimportkSensorfromkwave.ksourceimportkSourcefromkwave.optionsimportSimulationExecutionOptions,SimulationOptions
[docs]classTimeReversal:""" Time reversal reconstruction for photoacoustic imaging. This class handles time reversal reconstruction of initial pressure distribution from sensor data. It supports both 2D and 3D simulations and automatically applies compensation for half-plane recording. Args: kgrid: Computational grid for the simulation medium: Medium properties for wave propagation sensor: Sensor object containing the sensor mask compensation_factor: Factor to compensate for half-plane recording (default: 2.0) Raises: ValueError: If inputs are invalid for time reversal Note: Future versions may support: - GPU acceleration via use_gpu parameter - Differentiable operations via differentiable parameter - Custom boundary conditions via boundary_condition parameter - Elastic wave propagation via elastic parameter """
[docs]def__init__(self,kgrid:kWaveGrid,medium:kWaveMedium,sensor:kSensor,compensation_factor:float=2.0)->None:""" Initialize time reversal reconstruction. Args: kgrid: Computational grid for the simulation medium: Medium properties for wave propagation sensor: Sensor object containing the sensor mask compensation_factor: Factor to compensate for half-plane recording (default: 2.0) Raises: ValueError: If inputs are invalid for time reversal """self.kgrid=kgridself.medium=mediumself.sensor=sensorself.compensation_factor=compensation_factorself._source=Noneself._new_sensor=None# Validate inputsifsensor.maskisNone:raiseValueError("Sensor mask must be set for time reversal. Use sensor.mask = ...")# Check for valid time arrayifkgrid.t_arrayisNone:raiseValueError("t_array must be explicitly set for time reversal")ifisinstance(kgrid.t_array,str):ifkgrid.t_array=="auto":raiseValueError("t_array must be explicitly set for time reversal")else:raiseValueError(f"Invalid t_array value: {kgrid.t_array}")# Validate compensation factorifcompensation_factor<=0:raiseValueError("compensation_factor must be positive")# Validate sensor mask has at least one active pointifnotnp.any(sensor.mask):raiseValueError("Sensor mask must have at least one active point")# Validate sensor mask shape matches grid dimensionsifnotnp.array_equal(sensor.mask.shape,kgrid.N):raiseValueError(f"Sensor mask shape {sensor.mask.shape} does not match grid dimensions {kgrid.N}")self._passed_record=self.sensor.recordifself._passed_recordisNone:self._passed_record=[]if"p_final"notinself._passed_record:self._passed_record.append("p_final")
def__call__(self,simulation_function:Callable,simulation_options:SimulationOptions,execution_options:SimulationExecutionOptions)->np.ndarray:""" Run time reversal reconstruction. Args: simulation_function: Function to run the simulation (e.g., kspaceFirstOrder2D) simulation_options: Options for the simulation execution_options: Options for execution Returns: Reconstructed initial pressure distribution Raises: ValueError: If simulation_function, simulation_options, or execution_options are None, or if sensor does not have recorded pressure data """ifsimulation_functionisNone:raiseValueError("simulation_function must be provided")ifsimulation_optionsisNone:raiseValueError("simulation_options must be provided")ifexecution_optionsisNone:raiseValueError("execution_options must be provided")# 'recorded_pressure' is used as boundary data for time reversal reconstructionifnothasattr(self.sensor,"recorded_pressure")orself.sensor.recorded_pressureisNone:raiseValueError("Sensor must have recorded pressure data. Run a forward simulation first.")# Create source and sensor for reconstruction# The source is created with the same mask as the sensor and the recorded pressure is time-reversed and used as the source pressure.self._source=kSource()self._source.p_mask=self.sensor.mask# Use sensor mask as source maskself._source.p=np.flip(self.sensor.recorded_pressure,axis=1)# Time-reverse the recorded pressureself._source.p_mode="dirichlet"# Use dirichlet boundary conditionself._new_sensor=kSensor(mask=self.sensor.mask,record=self._passed_record)# Run reconstructionresult=simulation_function(self.kgrid,self._source,self._new_sensor,self.medium,simulation_options,execution_options)# Process resultifisinstance(result,dict):p0_recon=result["p_final"]else:p0_recon=result# Apply compensation factor and positivity conditionp0_recon=self.compensation_factor*p0_reconp0_recon[p0_recon<0]=0# Apply positivity conditionreturnp0_recon.T# Transpose since the values returned from the simulation function are transposed.