1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664 | ------
UVCal
------
UVCal objects hold all of the metadata and data required to work with calibration
solutions for interferometric data sets. Calibration solutions are tied to antennas
rather than baselines. There are many different kinds of calibration solutions, UVCal
has support for many of the most common ones, but this flexibility leads to some
complexity in the definition of UVCal objects. The ``cal_type`` attribute on UVCal
objects indicates whether calibration solutions are "gain" (a complex number per
antenna, polarization and frequency) or "delay" (a real number per antenna and
polarization) type solutions. The ``cal_style`` attribute indicates whether the solution
came from a "sky" or "redundant" style of calibration solution. Some metadata items only
apply to one ``cal_type`` or ``cal_style``.
The antennas are described in two ways: with antenna numbers and antenna names. The
antenna numbers should **not** be confused with indices -- they are not required to start
at zero or to be contiguous, although it is not uncommon for some telescopes to number
them like indices. On UVCal objects, the names and numbers are held in the
``antenna_names`` and ``antenna_numbers`` attributes respectively. These are arranged
in the same order so that an antenna number can be used to identify an antenna name and
vice versa.
Note that not all the antennas listed in ``antenna_numbers`` and ``antenna_names`` are
guaranteed to have calibration solutions associated with them in the ``gain_array``
(or ``delay_array`` for delay type solutions). The antenna numbers associated with each
calibration solution is held in the ``ant_array`` attribute (which has the same length
as the ``gain_array`` or ``delay_array`` along the antenna axis).
For most users, the convenience methods for quick data access (see
`UVCal: Quick data access`_) are the easiest way to get data for particular antennas.
Those methods take the antenna numbers (i.e. numbers listed in ``antenna_numbers``)
as inputs.
UVCal: parameter shape changes
-------------------------------
As detailed in :ref:`uvdata_future_shapes`, UVData objects now support flexible spectral
windows and will have several of their parameter shapes change in version 3.0. They also
have a method to convert to the planned future array shapes now to support an orderly
conversion of code and packages that use UVData objects to the future shapes.
UVCal objects now also support flexible spectral windows and will see parameter shape
changes in version 3.0.
Spectral windows are implemented on standard "gain" type UVCal objects in a similar way
to the UVData implementation, where windows are defined as sets of frequency channels
with some extra parameters to track which channels are in each spectral window. This
allows for spectral windows to have arbitrary numbers of frequency channels and makes
the ``channel_width`` parameter be an array of length ``Nfreqs`` rather than a scalar,
but only when the UVCal object contains flexible spectral windows. Supporting multiple
spectral windows in this way removes the need for the spectral window axis on several
UVCal parameters, but the axis was left as a length 1 axis for backwards compatibility.
Spectral windows are treated a little differently for wide-band style UVCal objects,
which do not have an explicit frequency axis. For those objects, which include all
"delay" type UVCal objects as well as wide-band gain objects, the ``freq_array``
and ``channel_width`` parameters are not required but the ``freq_range`` parameter is
required. UVCal objects that are wide-band and use the future array shapes
can support multiple spectral windows, see details below.
In version 3.0, several parameters will change shape. For standard "gain" type
UVCal objects, the length 1 axis that was originally intended for the spectral windows
axis will be removed from the ``gain_array`` , ``flag_array``, ``quality_array``,
``input_flag_array``, ``total_quality_array`` and ``freq_array`` parameters and the
``channel_width`` parameter will always be an array of length ``Nfreqs``. For
wide-band and "delay" type UVCal objects, the spectral window axis will be retained but
the axis corresponding to the frequency axis will be removed from the ``gain_array`` ,
``delay_array``, ``flag_array``, ``quality_array``, ``input_flag_array`` and the
``total_quality_array`` and the ``freq_range`` parameter will gain a spectral window
axis. In addition, the ``integration_time`` parameter will always be an array of
length ``Ntimes``.
In order to support an orderly conversion of code and packages that use the ``UVCal``
object to these new parameter shapes, we have created the
:meth:`pyuvdata.UVCal.use_future_array_shapes` method which will change the parameters
listed above to have their future shapes. Users writing new code that uses ``UVCal``
objects are encouraged to call that method immediately after creating a UVCal object
or reading in data from a file to ensure that the code will be compatible with the
forthcoming changes. Developers and maintainers of existing code that uses ``UVCal``
objects are encouraged to similarly add that method call and convert their code to use
the new shapes at their earliest convenience to ensure future compatibility. The method
will be deprecated but not removed in version 3.0 (it will just become a no-op) so
that code that calls it will continue to function.
UVCal: Reading/writing
----------------------
Calibration files using UVCal.
a) Reading a cal fits gain calibration file.
********************************************
.. code-block:: python
>>> import os
>>> import numpy as np
>>> import matplotlib.pyplot as plt # doctest: +SKIP
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> cal = UVCal()
>>> filename = os.path.join(DATA_PATH, 'zen.2457698.40355.xx.gain.calfits')
>>> cal.read_calfits(filename)
>>> # Cal type:
>>> print(cal.cal_type)
gain
>>> # number of calibration jones components and component type.
>>> print((cal.Njones, cal.jones_array))
(1, array([-5]))
>>> # Number of antennas with data
>>> print(cal.Nants_data)
19
>>> # Number of frequencies
>>> print(cal.Nfreqs)
10
>>> # Shape of the gain_array
>>> print(cal.gain_array.shape)
(19, 1, 10, 5, 1)
>>> # plot abs of all gains for first time and first jones component.
>>> for ant in range(cal.Nants_data): # doctest: +SKIP
... plt.plot(cal.freq_array.flatten(), np.abs(cal.gain_array[ant, 0, :, 0, 0]))
>>> plt.xlabel('Frequency (Hz)') # doctest: +SKIP
>>> plt.ylabel('Abs(gains)') # doctest: +SKIP
>>> plt.show() # doctest: +SKIP
b) FHD cal to cal fits
***********************
.. code-block:: python
>>> import os
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> obs_testfile = os.path.join(DATA_PATH, 'fhd_cal_data/1061316296_obs.sav')
>>> cal_testfile = os.path.join(DATA_PATH, 'fhd_cal_data/1061316296_cal.sav')
>>> settings_testfile = os.path.join(DATA_PATH, 'fhd_cal_data/1061316296_settings.txt')
>>> fhd_cal = UVCal()
>>> fhd_cal.read_fhd_cal(cal_testfile, obs_testfile, settings_file=settings_testfile)
>>> fhd_cal.write_calfits(os.path.join('.', 'tutorial_cal.fits'), clobber=True)
UVCal: Initializing from a UVData object
----------------------------------------
The :meth:`pyuvdata.UVCal.initialize_from_uvdata` method allows you to initialize a UVCal
object from the metadata in a UVData object. This is useful for codes that are calculating
calibration solutions from UVData objects. There are many optional parameters to allow
users to specify additional metadata or changes from the uvdata metadata. By default,
this method creats a metadata only UVCal object, but it can optionally create the
data-like arrays as well, filled with zeros.
.. code-block:: python
>>> import os
>>> from pyuvdata import UVData, UVCal
>>> from pyuvdata.data import DATA_PATH
>>> uvd_file = os.path.join(DATA_PATH, "zen.2458098.45361.HH.uvh5_downselected")
>>> uvd = UVData.from_file(uvd_file, file_type="uvh5")
>>> uvc = UVCal.initialize_from_uvdata(uvd, "multiply", "redundant")
>>> print(uvc.ant_array)
[ 0 1 11 12 13 23 24 25]
UVCal: Quick data access
------------------------
Method for quick data access, similar to those on :class:`pyuvdata.UVData`
(:ref:`quick_access`), are available for :class:`pyuvdata.UVCal`.
There are three specific methods that will return numpy arrays:
:meth:`pyuvdata.UVCal.get_gains`, :meth:`pyuvdata.UVCal.get_flags`, and
:meth:`pyuvdata.UVCal.get_quality`. When possible, these methods will return numpy
MemoryView objects, which is relatively fast and adds minimal memory overhead.
a) Data for a single antenna and instrumental polarization
**********************************************************
.. code-block:: python
>>> import os
>>> import numpy as np
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> UVC = UVCal()
>>> filename = os.path.join(DATA_PATH, 'zen.2457555.42443.HH.uvcA.omni.calfits')
>>> UVC.read_calfits(filename)
>>> gain = UVC.get_gains(9, 'Jxx') # gain for ant=9, pol='Jxx'
>>> # One can equivalently make any of these calls with the input wrapped in a tuple.
>>> gain = UVC.get_gains((9, 'Jxx'))
>>> # If no polarization is fed, then all polarizations are returned
>>> gain = UVC.get_gains(9)
>>> # One can also request flags and quality arrays in a similar manner
>>> flags = UVC.get_flags(9, 'Jxx')
>>> quals = UVC.get_quality(9, 'Jxx')
UVCal: Calibrating UVData
-------------------------
Calibration solutions in a :class:`pyuvdata.UVCal` object can be applied to a
:class:`pyuvdata.UVData` object using the :func:`pyuvdata.utils.uvcalibrate` function.
a) Calibration of UVData by UVCal
*********************************
.. code-block:: python
>>> # We can calibrate directly using a UVCal object
>>> import os
>>> from pyuvdata import UVData, UVCal, utils
>>> from pyuvdata.data import DATA_PATH
>>> uvd = UVData()
>>> uvd.read(os.path.join(DATA_PATH, "zen.2458098.45361.HH.uvh5_downselected"), file_type="uvh5")
>>> uvc = UVCal()
>>> uvc.read_calfits(os.path.join(DATA_PATH, "zen.2458098.45361.HH.omni.calfits_downselected"))
>>> # this is an old calfits file which has the wrong antenna names, so we need to fix them first.
>>> # fix the antenna names in the uvcal object to match the uvdata object
>>> uvc.antenna_names = np.array(
... [name.replace("ant", "HH") for name in uvc.antenna_names]
... )
>>> uvd_calibrated = utils.uvcalibrate(uvd, uvc, inplace=False)
>>> # We can also un-calibrate using the same UVCal
>>> uvd_uncalibrated = utils.uvcalibrate(uvd_calibrated, uvc, inplace=False, undo=True)
UVCal: Selecting data
---------------------
The :meth:`pyuvdata.UVCal.select` method lets you select specific antennas
(by number or name), frequencies (in Hz or by channel number), times or jones components
(by number or string) to keep in the object while removing others.
a) Select antennas to keep on UVCal object using the antenna number.
********************************************************************
.. code-block:: python
>>> import os
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> import numpy as np
>>> cal = UVCal()
>>> filename = os.path.join(DATA_PATH, "zen.2458098.45361.HH.omni.calfits_downselected")
>>> cal.read_calfits(filename)
>>> # print all the antennas numbers with data in the original file
>>> print(cal.ant_array)
[ 0 1 11 12 13 23 24 25]
>>> cal.select(antenna_nums=[1, 13, 25])
>>> # print all the antennas numbers with data after the select
>>> print(cal.ant_array)
[ 1 13 25]
b) Select antennas to keep using the antenna names, also select frequencies to keep.
************************************************************************************
.. code-block:: python
>>> import os
>>> import numpy as np
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> cal = UVCal()
>>> filename = os.path.join(DATA_PATH, "zen.2458098.45361.HH.omni.calfits_downselected")
>>> cal.read_calfits(filename)
>>> # print all the antenna names with data in the original file
>>> print([cal.antenna_names[np.where(cal.antenna_numbers==a)[0][0]] for a in cal.ant_array])
['ant0', 'ant1', 'ant11', 'ant12', 'ant13', 'ant23', 'ant24', 'ant25']
>>> # print the first 10 frequencies in the original file
>>> print(cal.freq_array[0, 0:10])
[1.000000e+08 1.015625e+08 1.031250e+08 1.046875e+08 1.062500e+08
1.078125e+08 1.093750e+08 1.109375e+08 1.125000e+08 1.140625e+08]
>>> cal.select(antenna_names=['ant11', 'ant13', 'ant25'], freq_chans=np.arange(0, 4))
>>> # print all the antenna names with data after the select
>>> print([cal.antenna_names[np.where(cal.antenna_numbers==a)[0][0]] for a in cal.ant_array])
['ant11', 'ant13', 'ant25']
>>> # print all the frequencies after the select
>>> print(cal.freq_array)
[[1.000000e+08 1.015625e+08 1.031250e+08 1.046875e+08]]
d) Select times
***************
.. code-block:: python
>>> import os
>>> import numpy as np
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> cal = UVCal()
>>> filename = os.path.join(DATA_PATH, "zen.2458098.45361.HH.omni.calfits_downselected")
>>> cal.read_calfits(filename)
>>> # print all the times in the original file
>>> print(cal.time_array)
[2458098.45677626 2458098.45690053 2458098.45702481 2458098.45714908
2458098.45727336 2458098.45739763 2458098.45752191 2458098.45764619
2458098.45777046 2458098.45789474]
>>> # select the first 3 times
>>> cal.select(times=cal.time_array[0:3])
>>> print(cal.time_array)
[2458098.45677626 2458098.45690053 2458098.45702481]
d) Select Jones components
**************************
Selecting on Jones component can be done either using the component numbers or
the component strings (e.g. "Jxx" or "Jyy" for linear polarizations or "Jrr" or
"Jll" for circular polarizations). If ``x_orientation`` is set on the object, strings
represting the physical orientation of the dipole can also be used (e.g. "Jnn" or "ee).
.. code-block:: python
>>> import os
>>> import numpy as np
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> import pyuvdata.utils as uvutils
>>> cal = UVCal()
>>> filename = os.path.join(DATA_PATH, "zen.2458098.45361.HH.omni.calfits_downselected")
>>> cal.read_calfits(filename)
>>> # Jones component numbers can be found in the jones_array
>>> print(cal.jones_array)
[-5 -6]
>>> # Jones component numbers can be converted to strings using a utility function
>>> print(uvutils.jnum2str(cal.jones_array))
['Jxx', 'Jyy']
>>> # make a copy of the object and select Jones components using the component numbers
>>> cal2 = cal.copy()
>>> cal2.select(jones=[-5])
>>> # print Jones component numbers and strings after select
>>> print(cal2.jones_array)
[-5]
>>> print(uvutils.jnum2str(cal2.jones_array))
['Jxx']
>>> # make a copy of the object and select Jones components using the component strings
>>> cal2 = cal.copy()
>>> cal2.select(jones=["Jxx"])
>>> # print Jones component numbers and strings after select
>>> print(cal2.jones_array)
[-5]
>>> print(uvutils.jnum2str(cal2.jones_array))
['Jxx']
>>> # print x_orientation
>>> print(cal.x_orientation)
east
>>> # make a copy of the object and select Jones components using the physical orientation strings
>>> cal2 = cal.copy()
>>> cal2.select(jones=["Jee"])
>>> # print Jones component numbers and strings after select
>>> print(cal2.jones_array)
[-5]
>>> print(uvutils.jnum2str(cal2.jones_array))
['Jxx']
UVCal: Adding data
------------------
The :meth:`~pyuvdata.UVCal.__add__` method lets you combine UVCal objects along
the antenna, time, frequency, and/or polarization axis.
a) Add frequencies.
*******************
.. code-block:: python
>>> import os
>>> import numpy as np
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> cal1 = UVCal()
>>> filename = os.path.join(DATA_PATH, 'zen.2457698.40355.xx.gain.calfits')
>>> cal1.read_calfits(filename)
>>> cal2 = cal1.copy()
>>> # Downselect frequencies to recombine
>>> cal1.select(freq_chans=np.arange(0, 5))
>>> cal2.select(freq_chans=np.arange(5, 10))
>>> cal3 = cal1 + cal2
>>> print((cal1.Nfreqs, cal2.Nfreqs, cal3.Nfreqs))
(5, 5, 10)
b) Add times.
****************
.. code-block:: python
>>> import os
>>> import numpy as np
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> cal1 = UVCal()
>>> filename = os.path.join(DATA_PATH, 'zen.2457698.40355.xx.gain.calfits')
>>> cal1.read_calfits(filename)
>>> cal2 = cal1.copy()
>>> # Downselect times to recombine
>>> times = np.unique(cal1.time_array)
>>> cal1.select(times=times[0:len(times) // 2])
>>> cal2.select(times=times[len(times) // 2:])
>>> cal3 = cal1 + cal2
>>> print((cal1.Ntimes, cal2.Ntimes, cal3.Ntimes))
(2, 3, 5)
c) Adding in place.
*******************
The following two commands are equivalent, and act on cal1
directly without creating a third uvcal object.
.. code-block:: python
>>> import os
>>> import numpy as np
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> cal1 = UVCal()
>>> filename = os.path.join(DATA_PATH, 'zen.2457698.40355.xx.gain.calfits')
>>> cal1.read_calfits(filename)
>>> cal2 = cal1.copy()
>>> times = np.unique(cal1.time_array)
>>> cal1.select(times=times[0:len(times) // 2])
>>> cal2.select(times=times[len(times) // 2:])
>>> cal1.__add__(cal2, inplace=True)
>>> cal1.read_calfits(filename)
>>> cal2 = cal1.copy()
>>> cal1.select(times=times[0:len(times) // 2])
>>> cal2.select(times=times[len(times) // 2:])
>>> cal1 += cal2
d) Reading multiple files.
**************************
If any of the read methods (:meth:`pyuvdata.UVCal.read_calfits`,
:meth:`pyuvdata.UVCal.read_fhd_cal`) are given a list of files,
each file will be read in succession and added to the previous.
.. code-block:: python
>>> import os
>>> import numpy as np
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> cal = UVCal()
>>> filename = os.path.join(DATA_PATH, 'zen.2457698.40355.xx.gain.calfits')
>>> cal.read_calfits(filename)
>>> cal1 = cal.select(freq_chans=np.arange(0, 2), inplace=False)
>>> cal2 = cal.select(freq_chans=np.arange(2, 4), inplace=False)
>>> cal3 = cal.select(freq_chans=np.arange(4, 7), inplace=False)
>>> cal1.write_calfits(os.path.join('.', 'tutorial1.fits'))
>>> cal2.write_calfits(os.path.join('.', 'tutorial2.fits'))
>>> cal3.write_calfits(os.path.join('.', 'tutorial3.fits'))
>>> filenames = [os.path.join('.', f) for f
... in ['tutorial1.fits', 'tutorial2.fits', 'tutorial3.fits']]
>>> cal.read_calfits(filenames)
>>> # For FHD cal datasets pass lists for each file type
>>> fhd_cal = UVCal()
>>> obs_testfiles = [os.path.join(DATA_PATH, f) for f
... in ['fhd_cal_data/1061316296_obs.sav',
... 'fhd_cal_data/set2/1061316296_obs.sav']]
>>> cal_testfiles = [os.path.join(DATA_PATH, f) for f
... in ['fhd_cal_data/1061316296_cal.sav',
... 'fhd_cal_data/set2/1061316296_cal.sav']]
>>> settings_testfiles = [os.path.join(DATA_PATH, f) for f
... in ['fhd_cal_data/1061316296_settings.txt',
... 'fhd_cal_data/set2/1061316296_settings.txt']]
>>> fhd_cal.read_fhd_cal(cal_testfiles, obs_testfiles, settings_file=settings_testfiles)
diffuse_model parameter value is a string, values are different
UVCal: Sorting data along various axes
---------------------------------------
Methods exist for sorting data along all the data axes to support comparisons between
UVCal objects and software access patterns.
a) Sorting along the antenna axis
*********************************
The :meth:`pyuvdata.UVCal.reorder_antennas` method will reorder the antenna axis by
sorting by antenna names or numbers, in ascending or descending order, or in an order
specified by passing an index array.
.. code-block:: python
>>> import os
>>> import numpy as np
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> cal = UVCal()
>>> filename = os.path.join(DATA_PATH, 'zen.2457698.40355.xx.gain.calfits')
>>> cal.read_calfits(filename)
>>> # Default is to order by antenna number
>>> cal.reorder_antennas()
>>> print(np.min(np.diff(cal.ant_array)) >= 0)
True
>>> # Prepend a ``-`` to the sort string to sort in descending order.
>>> cal.reorder_antennas('-number')
>>> print(np.min(np.diff(cal.ant_array)) <= 0)
True
b) Sorting along the frequency axis
***********************************
The :meth:`pyuvdata.UVCal.reorder_freqs` method will reorder the frequency axis by
sorting by spectral windows or channels (or even just the channels within specific
spectral windows). Spectral windows or channels can be sorted by ascending or descending
number or in an order specified by passing an index array for spectral window or
channels.
.. code-block:: python
>>> import os
>>> import numpy as np
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> cal = UVCal()
>>> filename = os.path.join(DATA_PATH, 'zen.2457698.40355.xx.gain.calfits')
>>> cal.read_calfits(filename)
>>> # First create a multi-spectral window UVCal object:
>>> cal._set_flex_spw()
>>> cal.channel_width = np.zeros(cal.Nfreqs, dtype=np.float64) + cal.channel_width
>>> cal.Nspws = 2
>>> cal.flex_spw_id_array = np.concatenate((np.ones(cal.Nfreqs // 2, dtype=int), np.full(cal.Nfreqs // 2, 2, dtype=int)))
>>> cal.spw_array = np.array([1, 2])
>>> spw2_inds = np.nonzero(cal.flex_spw_id_array == 2)[0]
>>> spw2_chan_width = cal.channel_width[0] * 2
>>> cal.freq_array[0, spw2_inds] = cal.freq_array[0, spw2_inds[0]] + spw2_chan_width * np.arange(spw2_inds.size)
>>> cal.channel_width[spw2_inds] = spw2_chan_width
>>> # Sort by spectral window number and by frequency within the spectral window
>>> # Now the spectral windows are in ascending order and the frequencies in each window
>>> # are in ascending order.
>>> cal.reorder_freqs(spw_order="number", channel_order="freq")
>>> print(cal.spw_array)
[1 2]
>>> print(np.min(np.diff(cal.freq_array[0, np.nonzero(cal.flex_spw_id_array == 1)])) >= 0)
True
>>> # Prepend a ``-`` to the sort string to sort in descending order.
>>> # Now the spectral windows are in descending order but the frequencies in each window
>>> # are in ascending order.
>>> cal.reorder_freqs(spw_order="-number", channel_order="freq")
>>> print(cal.spw_array)
[2 1]
>>> print(np.min(np.diff(cal.freq_array[0, np.nonzero(cal.flex_spw_id_array == 1)])) >= 0)
True
>>> # Use the ``select_spw`` keyword to sort only one spectral window.
>>> # Now the frequencies in spectral window 1 are in descending order but the frequencies
>>> # in spectral window 2 are in ascending order
>>> cal.reorder_freqs(select_spw=1, channel_order="-freq")
>>> print(np.min(np.diff(cal.freq_array[0, np.nonzero(cal.flex_spw_id_array == 1)])) <= 0)
True
>>> print(np.min(np.diff(cal.freq_array[0, np.nonzero(cal.flex_spw_id_array == 2)])) >= 0)
True
c) Sorting along the time axis
******************************
The :meth:`pyuvdata.UVCal.reorder_times` method will reorder the time axis by
sorting by time (ascending or descending) or in an order specified by passing an index
array for the time axis.
.. code-block:: python
>>> import os
>>> import numpy as np
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> cal = UVCal()
>>> filename = os.path.join(DATA_PATH, 'zen.2457698.40355.xx.gain.calfits')
>>> cal.read_calfits(filename)
>>> # Default is to order by ascending time
>>> cal.reorder_times()
>>> print(np.min(np.diff(cal.time_array)) >= 0)
True
>>> # Prepend a ``-`` to the sort string to sort in descending order.
>>> cal.reorder_times('-time')
>>> print(np.min(np.diff(cal.time_array)) <= 0)
True
d) Sorting along the Jones component axis
*****************************************
The :meth:`pyuvdata.UVCal.reorder_jones` method will reorder the Jones component axis
by the Jones component number or name, or by an explicit index ordering set by the user.
.. code-block:: python
>>> import os
>>> import numpy as np
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> cal = UVCal()
>>> filename = os.path.join(DATA_PATH, "zen.2458098.45361.HH.omni.calfits_downselected")
>>> cal.read_calfits(filename)
>>> # Default is to order by Jones component name
>>> cal.reorder_jones()
>>> print(cal.jones_array)
[-5 -6]
UVCal: Changing cal_type from 'delay' to 'gain'
-----------------------------------------------
UVCal includes the method :meth:`pyuvdata.UVCal.convert_to_gain`, which changes a
UVCal object's ``cal_type`` parameter from "delay" to "gain", and accordingly sets the
object's ``gain_array`` to an array consistent with its pre-existing ``delay_array``.
.. code-block:: python
>>> import os
>>> from pyuvdata import UVCal
>>> from pyuvdata.data import DATA_PATH
>>> cal = UVCal()
>>> # This file has a cal_type of 'delay'.
>>> filename = os.path.join(DATA_PATH, 'zen.2457698.40355.xx.delay.calfits')
>>> cal.read_calfits(filename)
>>> print(cal.cal_type)
delay
>>> # But we can convert it to a 'gain' type calibration.
>>> cal.convert_to_gain()
>>> print(cal.cal_type)
gain
>>> # If we want the calibration to use a positive value in its exponent, rather
>>> # than the default negative value:
>>> cal = UVCal()
>>> cal.read_calfits(filename)
>>> cal = cal.convert_to_gain(delay_convention='plus')
>>> # Convert to gain *without* running the default check that internal arrays are
>>> # of compatible shapes:
>>> cal = UVCal()
>>> cal.read_calfits(filename)
>>> cal.convert_to_gain(run_check=False)
>>> # Convert to gain *without* running the default check that optional parameters
>>> # are properly shaped and typed:
>>> cal = UVCal()
>>> cal.read_calfits(filename)
>>> cal.convert_to_gain(check_extra=False)
>>> # Convert to gain *without* running the default checks on the reasonableness
>>> # of the resulting calibration's parameters.
>>> cal = UVCal()
>>> cal.read_calfits(filename)
>>> cal.convert_to_gain(run_check_acceptability=False)
|