Skip to content

Commit bc1847c

Browse files
author
sambit-giri
committed
docstring updated
1 parent 1844045 commit bc1847c

2 files changed

Lines changed: 290 additions & 162 deletions

File tree

src/tools21cm/radio_telescope_calibration.py

Lines changed: 129 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,42 @@
1212
from . import conv
1313
from . import cosmo as cm
1414
from . import smoothing as sm
15-
import scipy
1615
from glob import glob
1716
from time import time, sleep
1817
import pickle
1918
from joblib import cpu_count, Parallel, delayed
2019
from tqdm import tqdm
2120

22-
2321
def from_antenna_config_with_gains(antxyz, z, nu=None,
2422
gain_model={'name': 'random_uniform', 'min': 0.5, 'max': 1.1}):
2523
"""
26-
The function reads the antenna positions (N_ant antennas) from the file given.
24+
Calculates baselines and complex gain products for an antenna array.
25+
26+
This function takes antenna positions, generates complex gain values for each
27+
antenna based on a specified model, and then computes the baseline vectors
28+
(u,v,w). For each baseline, it also calculates the four products of the
29+
complex gains (g_i * g_j*) which are g_r*g_r, g_i*g_i, g_r*g_i, g_i*g_r.
2730
2831
Parameters
2932
----------
30-
antxyz: ndarray
31-
The radio telescope antenna configuration.
32-
z : float
33-
Redhsift of the slice observed.
34-
nu : float
35-
The frequency observed by the telescope.
33+
antxyz: astropy.Quantity
34+
An object with antenna positions, expected to have a `.to('m').value` method.
35+
z : float
36+
Redshift of the slice observed.
37+
nu : float, optional
38+
The frequency observed by the telescope in MHz. If None, it's calculated from z.
39+
gain_model : dict or numpy.ndarray, optional
40+
Specifies how to generate antenna gains. Can be a dict defining a
41+
distribution ('random_gaussian' or 'random_uniform') or a pre-computed
42+
array of complex gains.
3643
3744
Returns
3845
-------
39-
Nbase : ndarray
40-
Numpy array (N_ant(N_ant-1)/2 x 3) containing the (ux,uy,uz) values derived
41-
from the antenna positions.
42-
N_ant : int
43-
Number of antennas.
46+
Nbase : numpy.ndarray
47+
Array of shape `(n_baselines, 7)` containing `(u,v,w)` and the four
48+
gain product components for each baseline.
49+
N_ant : int
50+
The total number of antennas in the configuration.
4451
"""
4552
z = float(z)
4653
if antxyz is None:
@@ -102,41 +109,48 @@ def get_uv_map_with_gains(ncells, z,
102109
subarray_type="AA4", total_int_time=6., int_time=10., boxsize=None, declination=-30.,
103110
include_mirror_baselines=False, verbose=True):
104111
"""
105-
Create the gain and uv maps with individual gain values for each baseline stored per pixel.
112+
Creates a UV map where each grid cell accumulates complex gain information.
113+
114+
This function simulates a radio observation over time, accounting for
115+
evolving instrumental gains. It iterates through time steps, periodically
116+
re-calculating antenna gains, applying Earth rotation, and gridding the
117+
resulting baseline tracks. The output map stores the number of hits and the
118+
sum of four gain products for each UV cell.
106119
107120
Parameters
108121
----------
109122
ncells : int
110123
Number of cells in each dimension of the grid.
111124
z : float
112-
Redshift.
125+
Redshift of the observation.
113126
gain_model : dict or function
114-
Gain model parameters or a custom function that returns random gain values.
115-
gain_timescale : list
116-
Timescale after which gain values will evolve.
117-
subarray_type: str
118-
The name of the SKA-Low layout configuration.
127+
Model for generating antenna gains. Passed to `from_antenna_config_with_gains`.
128+
gain_timescale : list of int
129+
Timescales (in seconds) at which gain values are re-calculated.
130+
subarray_type : str
131+
The name of the telescope layout configuration (e.g., "AA4").
119132
total_int_time : float
120-
Total observation time per day (in hours).
133+
Total observation time, in hours.
121134
int_time : float
122-
Integration time (in seconds).
135+
Integration time per snapshot, in seconds.
123136
declination : float
124-
Declination angle in degrees.
125-
boxsize : float
126-
Size of the observed sky area in Mpc.
137+
Declination of the pointing center, in degrees.
138+
boxsize : float, optional
139+
Comoving size of the observed sky area, in Mpc.
127140
include_mirror_baselines : bool
128-
Whether to include mirror baselines.
141+
If True, grids both (u,v) and (-u,-v) tracks.
129142
verbose : bool
130-
If True, enables verbose output.
143+
If True, enables progress bars and informational messages.
131144
132145
Returns
133146
-------
134-
uv_map : ndarray
135-
Array of lists, each containing gain values for the pixel.
147+
gain_uv_map : numpy.ndarray
148+
A 3D array of shape `(ncells, ncells, 5)`. For each UV cell (i,j),
149+
`gain_uv_map[i,j,0]` is the hit count, and the other 4 channels are
150+
the accumulated sums of the gain products.
136151
N_ant : int
137-
Number of antennas.
152+
The total number of antennas.
138153
"""
139-
140154
# Load the antenna configuration with gains only once
141155
if verbose:
142156
print("Loading antenna configuration with gains...")
@@ -161,38 +175,43 @@ def get_uv_map_with_gains(ncells, z,
161175
rotated_Nbase = earth_rotation_effect(Nbase[:,:3], time_idx, int_time, declination)
162176

163177
# Grid the rotated baselines with gain values
164-
grid_uv_tracks_with_gains(rotated_Nbase, Nbase[:,3:], gain_uv_map, z, ncells,
178+
_grid_uv_tracks_with_gains(rotated_Nbase, Nbase[:,3:], gain_uv_map, z, ncells,
165179
boxsize=boxsize, include_mirror_baselines=include_mirror_baselines)
166180

167181
if verbose:
168182
print("UV map generation complete.")
169183

170184
return gain_uv_map, N_ant
171185

172-
def grid_uv_tracks_with_gains(Nbase, gain_vals, gain_uv_map, z, ncells, boxsize=None, include_mirror_baselines=False, verbose=True):
186+
def _grid_uv_tracks_with_gains(Nbase, gain_vals, gain_uv_map, z, ncells, boxsize=None, include_mirror_baselines=False, verbose=True):
173187
"""
174-
Grid uv tracks with gain values on a grid, storing individual gain values for each baseline at each pixel.
188+
Grids UV tracks and accumulates gain values for a single time snapshot.
189+
190+
This function projects rotated baseline coordinates onto a 2D grid. For each
191+
grid cell, it increments a hit counter and adds the four gain product
192+
components of any baseline that falls into that cell.
175193
176194
Parameters
177195
----------
178-
Nbase : ndarray
179-
Array containing ux, uy, uz values of the antenna configuration.
180-
gain_vals : ndarray
181-
Array containing gain values for each baseline.
182-
uv_map : ndarray
183-
2D array of lists, each containing gain values for the respective grid pixel.
196+
Nbase : numpy.ndarray
197+
Array `(n_baselines, 3)` of rotated (u, v, w) coordinates.
198+
gain_vals : numpy.ndarray
199+
Array `(n_baselines, 4)` of gain products for each baseline.
200+
gain_uv_map : numpy.ndarray
201+
The 3D output array `(ncells, ncells, 5)` to be modified in-place.
184202
z : float
185-
Redshift of the slice observed.
203+
Redshift of the observation slice.
186204
ncells : int
187-
Number of cells in the grid.
205+
Number of cells in one dimension of the target grid.
188206
boxsize : float, optional
189-
Comoving size of the sky observed. Defaults to a predefined constant if None.
207+
Comoving size of the sky observed in Mpc.
190208
include_mirror_baselines : bool, optional
191-
If True, includes mirror baselines.
209+
If True, also grids the hermitian conjugate baselines at (-u, -v).
192210
193211
Returns
194212
-------
195-
None : Modifies uv_map in-place to store gain values.
213+
None
214+
Modifies `gain_uv_map` in-place.
196215
"""
197216
if boxsize is None:
198217
boxsize = conv.LB # Default boxsize (assumed defined globally or elsewhere)
@@ -229,21 +248,26 @@ def gain_uv_map_to_uv_map(gain_uv_map):
229248

230249
def apply_uv_with_gains_response_on_image(array, gain_uv_map, verbose=True):
231250
"""
232-
Apply the effect of radio observation strategy with varied antenna/baseline gains on an image.
233-
251+
Applies the instrumental response, including gains, to a sky image.
252+
253+
This function simulates the effect of observing a true sky image with an
254+
interferometer that has complex antenna gains. It operates in the Fourier
255+
domain by multiplying the Fourier transform of the sky by an effective
256+
complex gain derived from the simulated observation.
257+
234258
Parameters
235259
----------
236-
array : ndarray
237-
The input image array.
238-
gain_uv_map : ndarray of lists
239-
The uv_map, where each entry is a list of gain values for that pixel.
260+
array : numpy.ndarray
261+
The 2D input sky image.
262+
gain_uv_map : numpy.ndarray
263+
The 3D UV map `(ncells, ncells, 5)` from `get_uv_map_with_gains`.
240264
verbose : bool, optional
241-
If True, enables verbose progress output using tqdm.
242-
265+
(Currently unused).
266+
243267
Returns
244268
-------
245-
img_map : ndarray
246-
The resulting radio image after applying the uv_map with gains in the Fourier domain.
269+
img_map : numpy.ndarray
270+
The resulting 2D "dirty" image after applying the instrumental response.
247271
"""
248272
assert array.shape == gain_uv_map[:,:,0].shape, "Array and uv_map must have the same shape"
249273

@@ -261,24 +285,26 @@ def apply_uv_with_gains_response_on_image(array, gain_uv_map, verbose=True):
261285

262286
def from_antenna_config_with_antenna_stamp(antxyz, z, nu=None):
263287
"""
264-
The function reads the antenna positions (N_ant antennas) from the file given.
288+
Calculates baselines and attaches unique integer tags for each antenna.
289+
290+
This function converts antenna positions into baseline vectors (u,v,w) and,
291+
for each baseline, stores the integer tags of the two antennas that form it.
265292
266293
Parameters
267294
----------
268-
subarray_type: str
269-
The name of the SKA-Low layout configuration.
270-
z : float
271-
Redhsift of the slice observed.
272-
nu : float
273-
The frequency observed by the telescope.
295+
antxyz: astropy.Quantity
296+
An object with antenna positions, expected to have a `.to('m').value` method.
297+
z : float
298+
Redshift of the slice observed.
299+
nu : float, optional
300+
The frequency observed by the telescope in MHz. If None, it's calculated from z.
274301
275302
Returns
276303
-------
277-
Nbase : ndarray
278-
Numpy array (N_ant(N_ant-1)/2 x 3) containing the (ux,uy,uz) values derived
279-
from the antenna positions.
280-
N_ant : int
281-
Number of antennas.
304+
Nbase : numpy.ndarray
305+
Array `(n_baselines, 5)` containing `(u,v,w, ant_tag1, ant_tag2)`.
306+
N_ant : int
307+
The total number of antennas.
282308
"""
283309
z = float(z)
284310
if antxyz is None:
@@ -320,7 +346,7 @@ def get_full_uv_map_with_antenna_stamp(ncells, z, subarray_type="AA4", total_int
320346
z : float
321347
Redshift.
322348
subarray_type: str
323-
The name of the SKA-Low layout configuration.
349+
The name of the SKA-Low layout configuration.
324350
total_int_time : float
325351
Total observation time per day (in hours).
326352
int_time : float
@@ -365,7 +391,7 @@ def get_full_uv_map_with_antenna_stamp(ncells, z, subarray_type="AA4", total_int
365391

366392
# Parallel processing with progress bar for the first chunk
367393
results = Parallel(n_jobs=n_jobs)(
368-
delayed(process_chunk_get_full_uv_map_with_antenna_stamp)(
394+
delayed(_process_chunk_get_full_uv_map_with_antenna_stamp)(
369395
chunk_start, chunk_end, ncells, z, Nbase, int_time, declination, boxsize, include_mirror_baselines, verbose, show_progress=(i == 0))
370396
for i, (chunk_start, chunk_end) in enumerate(chunks)
371397
)
@@ -378,7 +404,7 @@ def get_full_uv_map_with_antenna_stamp(ncells, z, subarray_type="AA4", total_int
378404

379405
return ant_tag_uv_map, N_ant
380406

381-
def process_chunk_get_full_uv_map_with_antenna_stamp(chunk_start, chunk_end, ncells, z, Nbase, int_time, declination, boxsize, include_mirror_baselines, verbose, show_progress):
407+
def _process_chunk_get_full_uv_map_with_antenna_stamp(chunk_start, chunk_end, ncells, z, Nbase, int_time, declination, boxsize, include_mirror_baselines, verbose, show_progress):
382408
"""
383409
Process a chunk of time slices.
384410
@@ -424,36 +450,50 @@ def process_chunk_get_full_uv_map_with_antenna_stamp(chunk_start, chunk_end, nce
424450

425451
for time_idx in time_indices:
426452
rotated_Nbase = earth_rotation_effect(Nbase[:, :3], time_idx, int_time, declination)
427-
grid_uv_tracks_with_antenna_stamp(rotated_Nbase, Nbase[:, 3:], ant_tag_uv_map_chunk, z, ncells, time_idx - chunk_start,
453+
_grid_uv_tracks_with_antenna_stamp(rotated_Nbase, Nbase[:, 3:], ant_tag_uv_map_chunk, z, ncells, time_idx - chunk_start,
428454
boxsize=boxsize, include_mirror_baselines=include_mirror_baselines)
429455

430456
return ant_tag_uv_map_chunk
431457

432-
def grid_uv_tracks_with_antenna_stamp(Nbase, ant_tag, ant_tag_uv_map, z, ncells, time_idx,
458+
def _grid_uv_tracks_with_antenna_stamp(Nbase, ant_tag, ant_tag_uv_map, z, ncells, time_idx,
433459
boxsize=None, include_mirror_baselines=False, verbose=True):
434460
"""
435-
Grid uv tracks with gain values on a grid, storing individual gain values for each baseline at each pixel.
461+
Grids UV tracks with antenna tags onto a 2D grid for a single time snapshot.
462+
463+
This function takes the rotated baseline coordinates for a single moment,
464+
projects them onto a 2D grid, and for each grid cell (pixel), it appends
465+
the antenna pair tags of all baselines that fall into that cell.
436466
437467
Parameters
438468
----------
439-
Nbase : ndarray
440-
Array containing ux, uy, uz values of the antenna configuration.
441-
gain_vals : ndarray
442-
Array containing gain values for each baseline.
443-
uv_map : ndarray
444-
2D array of lists, each containing gain values for the respective grid pixel.
469+
Nbase : numpy.ndarray
470+
Array of shape `(n_baselines, 3)` containing the rotated (u, v, w)
471+
baseline coordinates for a single time step.
472+
ant_tag : numpy.ndarray
473+
Array of shape `(n_baselines, 2)` containing the integer tags for
474+
each antenna pair.
475+
ant_tag_uv_map : numpy.ndarray
476+
The 3D output array of shape `(n_timesteps, ncells, ncells)` where each
477+
element is a list. This function appends `[ant1, ant2]` pairs to these
478+
lists. It is modified in-place.
445479
z : float
446-
Redshift of the slice observed.
480+
Redshift of the observation slice.
447481
ncells : int
448-
Number of cells in the grid.
482+
Number of cells in one dimension of the target grid.
483+
time_idx : int
484+
The time index within the `ant_tag_uv_map` to populate.
449485
boxsize : float, optional
450-
Comoving size of the sky observed. Defaults to a predefined constant if None.
486+
Comoving size of the sky observed in Mpc. Defaults to a predefined
487+
constant if None.
451488
include_mirror_baselines : bool, optional
452-
If True, includes mirror baselines.
489+
If True, includes mirror baselines. (Note: Not yet implemented).
490+
verbose : bool, optional
491+
Enables verbose output. (Note: Currently unused in this function).
453492
454493
Returns
455494
-------
456-
None : Modifies uv_map in-place to store gain values.
495+
None
496+
Modifies `ant_tag_uv_map` in-place.
457497
"""
458498
if boxsize is None:
459499
boxsize = conv.LB # Default boxsize (assumed defined globally or elsewhere)
@@ -550,7 +590,7 @@ def get_full_uv_lagrangian_with_antenna_stamp(ncells, z, subarray_type="AA4", to
550590

551591
# Parallel processing with progress bar for the first chunk
552592
results = Parallel(n_jobs=n_jobs)(
553-
delayed(process_chunk_get_full_uv_lagrangian_with_antenna_stamp)(
593+
delayed(_process_chunk_get_full_uv_lagrangian_with_antenna_stamp)(
554594
chunk_start, chunk_end, ncells, z, Nbase, int_time, declination, boxsize, include_mirror_baselines, verbose, show_progress=(i == 0))
555595
for i, (chunk_start, chunk_end) in enumerate(chunks)
556596
)
@@ -564,7 +604,7 @@ def get_full_uv_lagrangian_with_antenna_stamp(ncells, z, subarray_type="AA4", to
564604
ant_pairs = Nbase[:,-2:]
565605
return ant_tag_uv_lagr, ant_pairs
566606

567-
def process_chunk_get_full_uv_lagrangian_with_antenna_stamp(chunk_start, chunk_end, ncells, z, Nbase, int_time, declination, boxsize, include_mirror_baselines, verbose, show_progress):
607+
def _process_chunk_get_full_uv_lagrangian_with_antenna_stamp(chunk_start, chunk_end, ncells, z, Nbase, int_time, declination, boxsize, include_mirror_baselines, verbose, show_progress):
568608
"""
569609
Processes a chunk of observation time slices for parallel computation.
570610
@@ -611,12 +651,12 @@ def process_chunk_get_full_uv_lagrangian_with_antenna_stamp(chunk_start, chunk_e
611651

612652
for time_idx in time_indices:
613653
rotated_Nbase = earth_rotation_effect(Nbase[:, :3], time_idx, int_time, declination)
614-
grid_uv_lagrangian_tracks_with_antenna_stamp(rotated_Nbase, Nbase[:, 3:], ant_tag_uv_map_chunk, z, ncells, time_idx - chunk_start,
654+
_grid_uv_lagrangian_tracks_with_antenna_stamp(rotated_Nbase, Nbase[:, 3:], ant_tag_uv_map_chunk, z, ncells, time_idx - chunk_start,
615655
boxsize=boxsize, include_mirror_baselines=include_mirror_baselines)
616656

617657
return ant_tag_uv_map_chunk
618658

619-
def grid_uv_lagrangian_tracks_with_antenna_stamp(Nbase, ant_tag, ant_tag_uv_map, z, ncells, time_idx,
659+
def _grid_uv_lagrangian_tracks_with_antenna_stamp(Nbase, ant_tag, ant_tag_uv_map, z, ncells, time_idx,
620660
boxsize=None, include_mirror_baselines=False, verbose=True):
621661
"""
622662
Grids UV tracks for a single time snapshot onto an integer grid.

0 commit comments

Comments
 (0)