|
| 1 | +""" |
| 2 | +Wrapper functions for producing time lag and cross-correlation maps from data cubes. |
| 3 | +""" |
| 4 | +import astropy.units as u |
| 5 | +import itertools |
| 6 | +import sunkit_image.time_lag |
| 7 | +import sunpy.map |
| 8 | + |
| 9 | +from synthesizAR.instruments.sdo import _AIA_CHANNEL_WAVELENGTHS |
| 10 | + |
| 11 | +import synthesizAR.analysis.time_lag.map_sources # NOQA |
| 12 | + |
| 13 | + |
| 14 | +__all__ = ['get_aia_channel_combinations', 'make_time_lag_map', 'make_cross_correlation_map'] |
| 15 | + |
| 16 | + |
| 17 | +def get_aia_channel_combinations(): |
| 18 | + """ |
| 19 | + Convenience function for listing all possible AIA channel pairs. |
| 20 | + This is useful for computing time lags. |
| 21 | + """ |
| 22 | + channel_list = [f"{chan.to_value('Angstrom'):.0f}" for chan in _AIA_CHANNEL_WAVELENGTHS] |
| 23 | + channel_combinations = list(itertools.combinations(channel_list, 2)) |
| 24 | + channel_combinations = channel_combinations[:5] + [sorted(c, key=lambda x: float(x), reverse=True) for c in channel_combinations[5:]] |
| 25 | + return channel_combinations |
| 26 | + |
| 27 | + |
| 28 | +def _get_meta_and_time(cube_a, cube_b, lag_bounds): |
| 29 | + time_a = cube_a.axis_world_coords('time')[0] |
| 30 | + time_b = cube_b.axis_world_coords('time')[0] |
| 31 | + if not (time_a == time_b).all(): |
| 32 | + raise ValueError('Time axes of both cubes must be the same') |
| 33 | + time = (time_a - time_a[0]).to('s') |
| 34 | + if lag_bounds is None: |
| 35 | + lag_bounds = u.Quantity([-time[-1]/2, time[-1]/2]) |
| 36 | + meta = cube_a.meta.copy() |
| 37 | + stale_keys = ['bunit', 'date_sim', 'wavelnth', 'waveunit', 'instrume', 'telescop', 'obsrvtry', 'detector'] |
| 38 | + for k in stale_keys: |
| 39 | + _ = meta.pop(k) |
| 40 | + meta['chan_a'] = cube_a.meta.get('wavelnth') |
| 41 | + meta['chan_b'] = cube_b.meta.get('wavelnth') |
| 42 | + return time, lag_bounds, meta |
| 43 | + |
| 44 | + |
| 45 | +@u.quantity_input |
| 46 | +def make_time_lag_map(cube_a, cube_b, lag_bounds: u.s=None): |
| 47 | + """ |
| 48 | + Coordinate-aware wrapper around `~sunkit_image.time_lag.time_lag` |
| 49 | +
|
| 50 | + Parameters |
| 51 | + ---------- |
| 52 | + cube_a : `~ndcube.NDCube` |
| 53 | + cube_b : `~ndcube.NDCube` |
| 54 | + lag_bounds : `~astropy.units.Quantity` |
| 55 | +
|
| 56 | + Return |
| 57 | + ------ |
| 58 | + : `~sunpy.map.GenericMap` |
| 59 | + """ |
| 60 | + time, lag_bounds, meta = _get_meta_and_time(cube_a, cube_b, lag_bounds) |
| 61 | + data = sunkit_image.time_lag.time_lag(cube_a.data, cube_b.data, time, lag_bounds=lag_bounds) |
| 62 | + meta['bunit'] = time.unit.to_string(format='FITS') |
| 63 | + meta['measrmnt'] = 'time_lag' |
| 64 | + return sunpy.map.Map(data, meta) |
| 65 | + |
| 66 | + |
| 67 | +@u.quantity_input |
| 68 | +def make_cross_correlation_map(cube_a, cube_b, lag_bounds: u.s=None): |
| 69 | + """ |
| 70 | + Coordinate-aware wrapper around `~sunkit_image.time_lag.max_cross_correlation` |
| 71 | +
|
| 72 | + Parameters |
| 73 | + ---------- |
| 74 | + cube_a : `~ndcube.NDCube` |
| 75 | + cube_b : `~ndcube.NDCube` |
| 76 | + lag_bounds : `~astropy.units.Quantity` |
| 77 | +
|
| 78 | + Return |
| 79 | + ------ |
| 80 | + : `~sunpy.map.GenericMap` |
| 81 | + """ |
| 82 | + time, lag_bounds, meta = _get_meta_and_time(cube_a, cube_b, lag_bounds) |
| 83 | + data = sunkit_image.time_lag.max_cross_correlation(cube_a.data, cube_b.data, time, lag_bounds=lag_bounds) |
| 84 | + meta['measrmnt'] = 'max_cross_correlation' |
| 85 | + return sunpy.map.Map(data, meta) |
0 commit comments