astrohack 1.0.0__tar.gz → 1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {astrohack-1.0.0/src/astrohack.egg-info → astrohack-1.0.2}/PKG-INFO +1 -1
- {astrohack-1.0.0 → astrohack-1.0.2}/pyproject.toml +1 -1
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/beamcut.py +2 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/core/beamcut.py +31 -11
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/core/extract_pointing.py +10 -5
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/core/image_comparison_tool.py +44 -9
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/extract_holog.py +4 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/image_comparison_tool.py +1 -1
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/io/beamcut_mds.py +7 -1
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/text.py +3 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/visualization/plot_tools.py +33 -2
- {astrohack-1.0.0 → astrohack-1.0.2/src/astrohack.egg-info}/PKG-INFO +1 -1
- {astrohack-1.0.0 → astrohack-1.0.2}/LICENSE +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/MANIFEST.in +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/README.rst +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/setup.cfg +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/__init__.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/antenna/__init__.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/antenna/antenna_surface.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/antenna/base_panel.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/antenna/panel_fitting.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/antenna/polygon_panel.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/antenna/ring_panel.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/antenna/telescope.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/cassegrain_ray_tracing.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/combine.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/beamcut.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/beamcut_mds.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/cassegrain_ray_tracing.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/combine.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/create_param_json.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/dask.config.yaml +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/extract_holog.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/extract_locit.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/extract_pointing.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/holog.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/holog_mds.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/image_comparison_tool.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/image_mds.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/locit.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/locit_mds.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/panel.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/panel_mds.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/point_mds.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/config/position_mds.param.json +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/core/__init__.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/core/cassegrain_ray_tracing.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/core/combine.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/core/extract_holog.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/core/extract_locit.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/core/holog.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/core/holog_obs_dict.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/core/locit.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/core/panel.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/aca_7m.zarr/.zattrs +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/aca_7m.zarr/.zgroup +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/aca_7m.zarr/.zmetadata +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/alma_da.zarr/.zattrs +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/alma_da.zarr/.zgroup +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/alma_da.zarr/.zmetadata +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/alma_dv.zarr/.zattrs +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/alma_dv.zarr/.zgroup +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/alma_dv.zarr/.zmetadata +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/alma_tp.zarr/.zattrs +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/alma_tp.zarr/.zgroup +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/alma_tp.zarr/.zmetadata +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/fix_telescope_files.bash +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/ngvla_proto_2025.zarr/.zattrs +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/ngvla_proto_2025.zarr/.zgroup +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/ngvla_proto_2025.zarr/.zmetadata +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/ngvla_proto_2025.zarr/point_cloud/.zarray +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/ngvla_proto_2025.zarr/point_cloud/0.0 +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/ngvla_proto_2025.zarr/qps_coefficients/.zarray +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/ngvla_proto_2025.zarr/qps_coefficients/0 +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/vla.zarr/.zattrs +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/vla.zarr/.zgroup +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/vla.zarr/.zmetadata +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/vlba.zarr/.zattrs +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/vlba.zarr/.zgroup +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/vlba.zarr/.zmetadata +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/extract_locit.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/extract_pointing.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/holog.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/io/__init__.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/io/base_mds.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/io/dio.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/io/holog_mds.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/io/image_mds.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/io/locit_mds.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/io/panel_mds.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/io/point_mds.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/io/position_mds.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/locit.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/panel.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/__init__.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/algorithms.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/constants.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/conversion.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/file.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/fits.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/graph.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/gridding.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/imaging.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/phase_fitting.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/ray_tracing_general.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/tools.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/validation.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/verification_tools.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/veritas.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/utils/zernike_aperture_fitting.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/visualization/__init__.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/visualization/array_cfg_plot.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/visualization/observation_summary.py +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack.egg-info/SOURCES.txt +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack.egg-info/dependency_links.txt +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack.egg-info/requires.txt +0 -0
- {astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: astrohack
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: Holography Antenna Commissioning Kit
|
|
5
5
|
Author-email: Joshua Hoskins <jhoskins@nrao.edu>, Victor de Souza Magalhaes <vdesouza@nrao.edu>, Jan-Willem Steeb <jsteeb@nrao.edu>
|
|
6
6
|
Requires-Python: <3.14,>=3.11
|
|
@@ -2,6 +2,7 @@ import pathlib
|
|
|
2
2
|
import numpy as np
|
|
3
3
|
|
|
4
4
|
from toolviper.utils.parameter import validate
|
|
5
|
+
import toolviper.utils.logger as logger
|
|
5
6
|
|
|
6
7
|
from astrohack.core.beamcut import process_beamcut_chunk
|
|
7
8
|
from astrohack.utils import get_default_file_name
|
|
@@ -143,6 +144,7 @@ def beamcut(
|
|
|
143
144
|
)
|
|
144
145
|
if executed_graph:
|
|
145
146
|
if destination is not None:
|
|
147
|
+
logger.info("Producing plots...")
|
|
146
148
|
beamcut_mds.plot_beamcut_in_amplitude(
|
|
147
149
|
destination,
|
|
148
150
|
lm_unit=lm_unit,
|
|
@@ -398,7 +398,9 @@ def _perform_curvefit_with_given_functions(
|
|
|
398
398
|
return False, np.full_like(initial_guesses, np.nan)
|
|
399
399
|
|
|
400
400
|
|
|
401
|
-
def _identify_pb_and_sidelobes_in_fit(
|
|
401
|
+
def _identify_pb_and_sidelobes_in_fit(
|
|
402
|
+
datalabel, x_data, fit_pars, primary_fwhm_estimate
|
|
403
|
+
):
|
|
402
404
|
"""
|
|
403
405
|
Identify primary beam and first sidelobes in fit using expected beam shape heuristics.
|
|
404
406
|
|
|
@@ -440,7 +442,16 @@ def _identify_pb_and_sidelobes_in_fit(datalabel, x_data, fit_pars):
|
|
|
440
442
|
i_pb_cen = np.argmin(np.abs(centers))
|
|
441
443
|
# This assumes the primary beam is the strongest
|
|
442
444
|
i_pb_amp = np.argmax(amps)
|
|
443
|
-
|
|
445
|
+
|
|
446
|
+
pb_problem = False
|
|
447
|
+
if i_pb_cen != i_pb_amp:
|
|
448
|
+
pb_problem = True
|
|
449
|
+
else:
|
|
450
|
+
if (
|
|
451
|
+
fwhms[i_pb_cen] < 0.5 * primary_fwhm_estimate
|
|
452
|
+
or fwhms[i_pb_cen] > 3.0 * primary_fwhm_estimate
|
|
453
|
+
):
|
|
454
|
+
pb_problem = True
|
|
444
455
|
|
|
445
456
|
if pb_problem:
|
|
446
457
|
logger.warning(f"Cannot reliably identify primary beam for {datalabel}.")
|
|
@@ -496,20 +507,29 @@ def _beamcut_multi_lobes_gaussian_fit(cut_xdtree, datalabel):
|
|
|
496
507
|
initial_guesses, bounds, n_peaks = _build_multi_gaussian_initial_guesses(
|
|
497
508
|
x_data, y_data, primary_fwhm
|
|
498
509
|
)
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
510
|
+
|
|
511
|
+
# This is a test for empty data
|
|
512
|
+
if np.nansum(y_data) == 0:
|
|
513
|
+
logger.warning(
|
|
514
|
+
f"{this_corr_data_label} appears to contain no valid data"
|
|
515
|
+
)
|
|
516
|
+
fit_succeeded = False
|
|
517
|
+
fit_pars = np.full_like(initial_guesses, np.nan)
|
|
518
|
+
else:
|
|
519
|
+
fit_succeeded, fit_pars = _perform_curvefit_with_given_functions(
|
|
520
|
+
x_data,
|
|
521
|
+
y_data,
|
|
522
|
+
initial_guesses,
|
|
523
|
+
bounds,
|
|
524
|
+
_multi_gaussian,
|
|
525
|
+
this_corr_data_label,
|
|
526
|
+
)
|
|
507
527
|
|
|
508
528
|
if fit_succeeded:
|
|
509
529
|
fit = _multi_gaussian(x_data, *fit_pars)
|
|
510
530
|
n_peaks, fit_pars, pb_center, pb_fwhm, first_side_lobe_ratio = (
|
|
511
531
|
_identify_pb_and_sidelobes_in_fit(
|
|
512
|
-
this_corr_data_label, x_data, fit_pars
|
|
532
|
+
this_corr_data_label, x_data, fit_pars, primary_fwhm
|
|
513
533
|
)
|
|
514
534
|
)
|
|
515
535
|
else:
|
|
@@ -179,7 +179,7 @@ def extract_pointing_chunk(pnt_params: dict, output_mds: AstrohackPointFile):
|
|
|
179
179
|
tb.close()
|
|
180
180
|
table_obj.close()
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
_evaluate_time_sampling(direction_time, ant_name)
|
|
183
183
|
|
|
184
184
|
pnt_xds = xr.Dataset()
|
|
185
185
|
coords = {"time": direction_time}
|
|
@@ -379,17 +379,22 @@ def _extract_scan_time_dict_jit(time, scan_ids, state_ids, ddi_ids, mapping_stat
|
|
|
379
379
|
return scan_time_dict
|
|
380
380
|
|
|
381
381
|
|
|
382
|
-
def
|
|
383
|
-
time_sampling, data_label, threshold=0.01, expected_interval=
|
|
382
|
+
def _evaluate_time_sampling(
|
|
383
|
+
time_sampling, data_label, threshold=0.01, expected_interval=None
|
|
384
384
|
):
|
|
385
|
+
intervals = np.diff(time_sampling)
|
|
386
|
+
unq_intervals, counts = np.unique(intervals, return_counts=True)
|
|
387
|
+
if expected_interval is None:
|
|
388
|
+
i_max_count = np.argmax(counts)
|
|
389
|
+
expected_interval = unq_intervals[i_max_count]
|
|
390
|
+
|
|
385
391
|
bin_sz = expected_interval / 4
|
|
386
392
|
time_bin_edge = np.arange(-bin_sz / 2, 2.5 * expected_interval, bin_sz)
|
|
387
393
|
time_bin_axis = time_bin_edge[:-1] + bin_sz / 2
|
|
388
394
|
i_mid = int(np.argmin(np.abs(time_bin_axis - expected_interval)))
|
|
389
395
|
|
|
390
|
-
intervals = np.diff(time_sampling)
|
|
391
396
|
hist, edges = np.histogram(intervals, bins=time_bin_edge)
|
|
392
|
-
n_total = np.
|
|
397
|
+
n_total = np.nansum(hist)
|
|
393
398
|
outlier_fraction = 1 - hist[i_mid] / n_total
|
|
394
399
|
|
|
395
400
|
if outlier_fraction > threshold:
|
|
@@ -127,7 +127,8 @@ class FITSImage:
|
|
|
127
127
|
"""
|
|
128
128
|
self.filename = fits_filename
|
|
129
129
|
self.telescope_name = telescope_name
|
|
130
|
-
|
|
130
|
+
fits_real_filename = fits_filename.split("/")[-1]
|
|
131
|
+
self.rootname = ".".join(fits_real_filename.split(".")[:-1]) + "."
|
|
131
132
|
self.header, self.data = read_fits(self.filename, header_as_dict=True)
|
|
132
133
|
stokes_iaxis = get_stokes_axis_iaxis(self.header)
|
|
133
134
|
|
|
@@ -152,12 +153,16 @@ class FITSImage:
|
|
|
152
153
|
self.y_axis, _, self.y_unit = get_axis_from_fits_header(
|
|
153
154
|
self.header, 2, pixel_offset=False
|
|
154
155
|
)
|
|
156
|
+
offset_scale = 1.5
|
|
157
|
+
x_offset = offset_scale * np.unique(np.diff(self.x_axis))[0]
|
|
158
|
+
y_offset = offset_scale * np.unique(np.diff(self.y_axis))[0]
|
|
159
|
+
self.x_axis = np.flip(self.x_axis + x_offset)
|
|
160
|
+
self.y_axis = np.flip(self.y_axis + y_offset)
|
|
155
161
|
self.x_unit = "m"
|
|
156
162
|
self.y_unit = "m"
|
|
157
163
|
elif "Astrohack" in self.header["ORIGIN"]:
|
|
158
164
|
self.x_axis, _, self.x_unit = get_axis_from_fits_header(self.header, 1)
|
|
159
165
|
self.y_axis, _, self.y_unit = get_axis_from_fits_header(self.header, 2)
|
|
160
|
-
self.data = np.fliplr(self.data)
|
|
161
166
|
else:
|
|
162
167
|
raise NotImplementedError(f'Unrecognized origin:\n{self.header["origin"]}')
|
|
163
168
|
self._create_base_mask()
|
|
@@ -208,11 +213,13 @@ class FITSImage:
|
|
|
208
213
|
x_mesh_dest, y_mesh_dest = np.meshgrid(
|
|
209
214
|
ref_image.x_axis, ref_image.y_axis, indexing="ij"
|
|
210
215
|
)
|
|
216
|
+
raveled_data = self.data.ravel()
|
|
217
|
+
valid_data = np.isfinite(raveled_data)
|
|
211
218
|
resamp = griddata(
|
|
212
|
-
(x_mesh_orig.ravel(), y_mesh_orig.ravel()),
|
|
213
|
-
|
|
219
|
+
(x_mesh_orig.ravel()[valid_data], y_mesh_orig.ravel()[valid_data]),
|
|
220
|
+
raveled_data[valid_data],
|
|
214
221
|
(x_mesh_dest.ravel(), y_mesh_dest.ravel()),
|
|
215
|
-
method="
|
|
222
|
+
method="nearest",
|
|
216
223
|
)
|
|
217
224
|
size = ref_image.x_axis.shape[0], ref_image.y_axis.shape[0]
|
|
218
225
|
self.x_axis = ref_image.x_axis
|
|
@@ -592,7 +599,15 @@ class FITSImage:
|
|
|
592
599
|
reorder_axis=False,
|
|
593
600
|
)
|
|
594
601
|
|
|
595
|
-
def scatter_plot(
|
|
602
|
+
def scatter_plot(
|
|
603
|
+
self,
|
|
604
|
+
destination,
|
|
605
|
+
ref_image,
|
|
606
|
+
dpi=300,
|
|
607
|
+
display=False,
|
|
608
|
+
max_radius=None,
|
|
609
|
+
min_radius=None,
|
|
610
|
+
):
|
|
596
611
|
"""
|
|
597
612
|
Produce a scatter plot of self.data agains ref_image.data
|
|
598
613
|
Args:
|
|
@@ -600,6 +615,8 @@ class FITSImage:
|
|
|
600
615
|
ref_image: Reference FITSImage object
|
|
601
616
|
dpi: png resolution on disk
|
|
602
617
|
display: Show interactive view of plot
|
|
618
|
+
max_radius: Maximum radius for scatter plot comparison as the outer panels can be crappy.
|
|
619
|
+
min_radius: Minimum radius for scatter plot comparison as the innermost panels can be crappy.
|
|
603
620
|
|
|
604
621
|
Returns:
|
|
605
622
|
None
|
|
@@ -610,10 +627,23 @@ class FITSImage:
|
|
|
610
627
|
|
|
611
628
|
fig, ax = plt.subplots(1, 1, figsize=[10, 8])
|
|
612
629
|
|
|
630
|
+
x_mesh_orig, y_mesh_orig = np.meshgrid(self.x_axis, self.y_axis, indexing="ij")
|
|
631
|
+
radius = np.sqrt(x_mesh_orig**2 + y_mesh_orig**2)
|
|
632
|
+
|
|
633
|
+
telescope = get_proper_telescope(self.telescope_name)
|
|
634
|
+
if min_radius is None:
|
|
635
|
+
min_radius = telescope.inner_radial_limit
|
|
636
|
+
if max_radius is None:
|
|
637
|
+
max_radius = telescope.outer_radial_limit - 1.0
|
|
613
638
|
scatter_mask = np.isfinite(ref_image.data)
|
|
614
639
|
scatter_mask = np.where(np.isfinite(self.data), scatter_mask, False)
|
|
640
|
+
scatter_mask = np.where(radius < max_radius, scatter_mask, False)
|
|
641
|
+
scatter_mask = np.where(radius > min_radius, scatter_mask, False)
|
|
642
|
+
|
|
615
643
|
ydata = self.data[scatter_mask]
|
|
616
644
|
xdata = ref_image.data[scatter_mask]
|
|
645
|
+
pl_max = np.max((np.max(xdata), np.max(ydata)))
|
|
646
|
+
pl_min = np.min((np.min(xdata), np.min(ydata)))
|
|
617
647
|
|
|
618
648
|
scatter_plot(
|
|
619
649
|
ax,
|
|
@@ -622,6 +652,12 @@ class FITSImage:
|
|
|
622
652
|
ydata,
|
|
623
653
|
f"{self.filename} [{self.unit}]",
|
|
624
654
|
add_regression=True,
|
|
655
|
+
regression_method="siegelslopes",
|
|
656
|
+
add_regression_reference=True,
|
|
657
|
+
regression_reference_label="Perfect agreement",
|
|
658
|
+
xlim=(pl_min, pl_max),
|
|
659
|
+
ylim=[pl_min, pl_max],
|
|
660
|
+
force_equal_aspect=True,
|
|
625
661
|
)
|
|
626
662
|
close_figure(
|
|
627
663
|
fig,
|
|
@@ -641,7 +677,6 @@ def image_comparison_chunk(compare_params):
|
|
|
641
677
|
Returns:
|
|
642
678
|
A DataTree containing the Image and its reference Image.
|
|
643
679
|
"""
|
|
644
|
-
|
|
645
680
|
image = FITSImage.from_fits_file(
|
|
646
681
|
compare_params["this_image"], compare_params["telescope_name"]
|
|
647
682
|
)
|
|
@@ -698,8 +733,8 @@ def image_comparison_chunk(compare_params):
|
|
|
698
733
|
if compare_params["plot_scatter"]:
|
|
699
734
|
image.scatter_plot(destination, ref_image, dpi=dpi, display=display)
|
|
700
735
|
|
|
701
|
-
img_node = xr.DataTree(name=image.
|
|
702
|
-
ref_node = xr.DataTree(name=ref_image.
|
|
736
|
+
img_node = xr.DataTree(name=image.rootname, dataset=image.export_as_xds())
|
|
737
|
+
ref_node = xr.DataTree(name=ref_image.rootname, dataset=ref_image.export_as_xds())
|
|
703
738
|
tree_node = xr.DataTree(
|
|
704
739
|
name=image.rootname[:-1], children={"Reference": ref_node, "Image": img_node}
|
|
705
740
|
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import pathlib
|
|
2
|
+
from copy import deepcopy
|
|
2
3
|
|
|
3
4
|
import toolviper.utils.parameter
|
|
4
5
|
import toolviper.utils.logger as logger
|
|
@@ -187,6 +188,9 @@ def extract_holog(
|
|
|
187
188
|
}
|
|
188
189
|
|
|
189
190
|
"""
|
|
191
|
+
# This copy here ensures that the user space holog_obs_dict given to extract_holog is not modified during execution
|
|
192
|
+
if holog_obs_dict is not None:
|
|
193
|
+
holog_obs_dict = deepcopy(holog_obs_dict)
|
|
190
194
|
|
|
191
195
|
# Doing this here allows it to get captured by locals()
|
|
192
196
|
holog_name = get_default_file_name(ms_name, ".holog.zarr", holog_name)
|
|
@@ -201,7 +201,7 @@ def rms_table_from_zarr_datatree(
|
|
|
201
201
|
raise FileNotFoundError
|
|
202
202
|
|
|
203
203
|
xdt = xr.open_datatree(input_params["zarr_data_tree"])
|
|
204
|
-
if xdt.attrs["
|
|
204
|
+
if xdt.attrs["origin_info"]["creator_function"] != "compare_fits_images":
|
|
205
205
|
logger.error("Data tree file was not created by astrohack.compare_fits_images")
|
|
206
206
|
raise ValueError
|
|
207
207
|
|
|
@@ -718,6 +718,8 @@ def _plot_single_cut_in_amplitude(cut_xds, axes, par_dict):
|
|
|
718
718
|
# Init
|
|
719
719
|
sub_title = _make_parallel_hand_sub_title(cut_xds.attrs)
|
|
720
720
|
max_amp = cut_xds.attrs["all_corr_ymax"]
|
|
721
|
+
if max_amp < 1e-2:
|
|
722
|
+
max_amp = 1.0
|
|
721
723
|
y_off = 0.05 * max_amp
|
|
722
724
|
lm_unit = par_dict["lm_unit"]
|
|
723
725
|
lm_fac = convert_unit("rad", lm_unit, "trigonometric")
|
|
@@ -944,7 +946,11 @@ def _plot_single_cut_in_attenuation(cut_xds, ax, par_dict):
|
|
|
944
946
|
x_data = lm_fac * cut_xds["lm_dist"].values
|
|
945
947
|
amps = cut_xds[f"{parallel_hand}_amplitude"].values
|
|
946
948
|
max_amp = np.max(amps)
|
|
947
|
-
|
|
949
|
+
if max_amp == 0:
|
|
950
|
+
y_data = np.full_like(x_data, -1)
|
|
951
|
+
else:
|
|
952
|
+
y_data = to_db(amps / max_amp)
|
|
953
|
+
|
|
948
954
|
y_min = np.min(y_data)
|
|
949
955
|
if y_min < min_attenuation:
|
|
950
956
|
min_attenuation = y_min
|
|
@@ -132,6 +132,9 @@ def get_default_file_name(
|
|
|
132
132
|
else:
|
|
133
133
|
output_filename = user_filename
|
|
134
134
|
|
|
135
|
+
if output_filename[-1] == "/":
|
|
136
|
+
output_filename = output_filename[:-1]
|
|
137
|
+
|
|
135
138
|
logger.info(f"Creating output file name: {output_filename}")
|
|
136
139
|
return output_filename
|
|
137
140
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import matplotlib.image
|
|
2
2
|
import numpy as np
|
|
3
|
-
from scipy.stats import linregress
|
|
3
|
+
from scipy.stats import linregress, theilslopes, siegelslopes
|
|
4
4
|
|
|
5
5
|
from matplotlib import pyplot as plt
|
|
6
6
|
from matplotlib.patches import Rectangle
|
|
@@ -251,6 +251,12 @@ def scatter_plot(
|
|
|
251
251
|
add_regression=False,
|
|
252
252
|
regression_linestyle="-",
|
|
253
253
|
regression_color="black",
|
|
254
|
+
regression_method="linregress",
|
|
255
|
+
add_regression_reference=False,
|
|
256
|
+
regression_reference=(1.0, 0.0),
|
|
257
|
+
regression_reference_color="orange",
|
|
258
|
+
regression_reference_label="Regression refrence",
|
|
259
|
+
force_equal_aspect=False,
|
|
254
260
|
add_legend=True,
|
|
255
261
|
legend_location="best",
|
|
256
262
|
):
|
|
@@ -287,6 +293,12 @@ def scatter_plot(
|
|
|
287
293
|
add_regression: Add a linear regression between X and y data
|
|
288
294
|
regression_linestyle: Line style for the regression plot
|
|
289
295
|
regression_color: Color for the regression plot
|
|
296
|
+
regression_method: Which scipy function to use for the linear regression: linregress, theilslopes or siegelslopes
|
|
297
|
+
add_regression_reference: Add reference for the expected regression result
|
|
298
|
+
regression_reference: 2 value array/tuple/list with a slope and intercept for reference
|
|
299
|
+
regression_reference_color: Color for reference regression
|
|
300
|
+
regression_reference_label: Label for reference regression
|
|
301
|
+
force_equal_aspect: Force equal aspect on plot box
|
|
290
302
|
add_legend: add legend to the plot
|
|
291
303
|
legend_location: Location of the legend in the plot
|
|
292
304
|
"""
|
|
@@ -325,7 +337,14 @@ def scatter_plot(
|
|
|
325
337
|
)
|
|
326
338
|
|
|
327
339
|
if add_regression:
|
|
328
|
-
|
|
340
|
+
if regression_method == "linregress":
|
|
341
|
+
slope, intercept, _, _, _ = linregress(xdata, ydata)
|
|
342
|
+
elif regression_method == "theilslopes":
|
|
343
|
+
slope, intercept, _, _ = theilslopes(ydata, xdata)
|
|
344
|
+
elif regression_method == "siegelslopes":
|
|
345
|
+
slope, intercept = siegelslopes(ydata, xdata)
|
|
346
|
+
else:
|
|
347
|
+
raise RuntimeError(f"Unknown linear regression method: {regression_method}")
|
|
329
348
|
regression_label = f"y = {slope:.4f}*x + {intercept:.4f}"
|
|
330
349
|
yregress = slope * xdata + intercept
|
|
331
350
|
ax.plot(
|
|
@@ -336,6 +355,15 @@ def scatter_plot(
|
|
|
336
355
|
label=regression_label,
|
|
337
356
|
lw=2,
|
|
338
357
|
)
|
|
358
|
+
if add_regression_reference:
|
|
359
|
+
reg_ref = regression_reference[0] * xdata + regression_reference[1]
|
|
360
|
+
ax.plot(
|
|
361
|
+
xdata,
|
|
362
|
+
reg_ref,
|
|
363
|
+
ls=regression_linestyle,
|
|
364
|
+
color=regression_reference_color,
|
|
365
|
+
label=regression_reference_label,
|
|
366
|
+
)
|
|
339
367
|
|
|
340
368
|
if model is not None:
|
|
341
369
|
ax.plot(
|
|
@@ -373,6 +401,9 @@ def scatter_plot(
|
|
|
373
401
|
ax_res.set_ylabel("Residuals")
|
|
374
402
|
ax_res.set_xlabel(xlabel)
|
|
375
403
|
|
|
404
|
+
if force_equal_aspect:
|
|
405
|
+
ax.set_aspect("equal", adjustable="box")
|
|
406
|
+
|
|
376
407
|
if title is not None:
|
|
377
408
|
ax.set_title(title)
|
|
378
409
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: astrohack
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: Holography Antenna Commissioning Kit
|
|
5
5
|
Author-email: Joshua Hoskins <jhoskins@nrao.edu>, Victor de Souza Magalhaes <vdesouza@nrao.edu>, Jan-Willem Steeb <jsteeb@nrao.edu>
|
|
6
6
|
Requires-Python: <3.14,>=3.11
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/ngvla_proto_2025.zarr/.zattrs
RENAMED
|
File without changes
|
{astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/ngvla_proto_2025.zarr/.zgroup
RENAMED
|
File without changes
|
{astrohack-1.0.0 → astrohack-1.0.2}/src/astrohack/data/telescopes/ngvla_proto_2025.zarr/.zmetadata
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|