jolly-roger 0.3.0__tar.gz → 0.4.0__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.
Potentially problematic release.
This version of jolly-roger might be problematic. Click here for more details.
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/PKG-INFO +4 -1
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/README.md +3 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/jolly_roger/_version.py +2 -2
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/jolly_roger/tractor.py +98 -23
- jolly_roger-0.4.0/jolly_roger/utils.py +28 -0
- jolly_roger-0.4.0/jolly_roger/wrap.py +51 -0
- jolly_roger-0.4.0/logo.png +0 -0
- jolly_roger-0.4.0/tests/test_wrap.py +64 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/.copier-answers.yml +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/.git_archival.txt +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/.gitattributes +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/.github/CONTRIBUTING.md +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/.github/actions/setup-deps/action.yml +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/.github/dependabot.yml +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/.github/release.yml +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/.github/workflows/cd.yml +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/.github/workflows/ci.yml +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/.gitignore +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/.pre-commit-config.yaml +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/.readthedocs.yaml +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/LICENSE +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/docs/conf.py +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/docs/index.md +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/jolly_roger/__init__.py +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/jolly_roger/_version.pyi +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/jolly_roger/baselines.py +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/jolly_roger/delays.py +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/jolly_roger/flagger.py +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/jolly_roger/hour_angles.py +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/jolly_roger/logging.py +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/jolly_roger/plots.py +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/jolly_roger/py.typed +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/jolly_roger/uvws.py +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/noxfile.py +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/pyproject.toml +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/tests/test_hour_angles.py +0 -0
- {jolly_roger-0.3.0 → jolly_roger-0.4.0}/tests/test_package.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jolly-roger
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: The pirate flagger
|
|
5
5
|
Project-URL: Homepage, https://github.com/flint-crew/jolly-roger
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/flint-crew/jolly-roger/issues
|
|
@@ -60,6 +60,9 @@ Description-Content-Type: text/markdown
|
|
|
60
60
|
|
|
61
61
|
The pirate flagger!
|
|
62
62
|
|
|
63
|
+
<img src="logo.png" alt="The Jolly Roger Flag" style="width:400px;"/>
|
|
64
|
+
|
|
65
|
+
|
|
63
66
|
# Installation
|
|
64
67
|
|
|
65
68
|
`pip install jolly-roger`
|
|
@@ -19,7 +19,9 @@ from tqdm.auto import tqdm
|
|
|
19
19
|
from jolly_roger.delays import data_to_delay_time, delay_time_to_data
|
|
20
20
|
from jolly_roger.logging import logger
|
|
21
21
|
from jolly_roger.plots import plot_baseline_comparison_data
|
|
22
|
+
from jolly_roger.utils import log_dataclass_attributes, log_jolly_roger_version
|
|
22
23
|
from jolly_roger.uvws import WDelays, get_object_delay_for_ms
|
|
24
|
+
from jolly_roger.wrap import calculate_nyquist_zone, symmetric_domain_wrap
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
@dataclass(frozen=True)
|
|
@@ -73,9 +75,12 @@ def tukey_taper(
|
|
|
73
75
|
|
|
74
76
|
if tukey_x_offset is not None:
|
|
75
77
|
x_freq = x_freq[:, None] - tukey_x_offset[None, :]
|
|
78
|
+
from jolly_roger.wrap import symmetric_domain_wrap
|
|
79
|
+
|
|
80
|
+
x_freq = symmetric_domain_wrap(values=x_freq, upper_limit=np.pi)
|
|
76
81
|
|
|
77
82
|
taper = np.ones_like(x_freq)
|
|
78
|
-
logger.debug(f"{x_freq.shape=} {type(x_freq)=}")
|
|
83
|
+
# logger.debug(f"{x_freq.shape=} {type(x_freq)=}")
|
|
79
84
|
# Fully zero region
|
|
80
85
|
taper[np.abs(x_freq) > outer_width] = 0
|
|
81
86
|
|
|
@@ -455,6 +460,7 @@ def make_plot_results(
|
|
|
455
460
|
before_delays = data_to_delay_time(data=before_baseline_data)
|
|
456
461
|
after_delays = data_to_delay_time(data=after_baseline_data)
|
|
457
462
|
|
|
463
|
+
logger.info("Creating figure")
|
|
458
464
|
# TODO: the baseline data and delay times could be put into a single
|
|
459
465
|
# structure to pass around easier.
|
|
460
466
|
plot_path = plot_baseline_comparison_data(
|
|
@@ -523,23 +529,32 @@ def _tukey_tractor(
|
|
|
523
529
|
"""
|
|
524
530
|
|
|
525
531
|
delay_time = data_to_delay_time(data=data_chunk)
|
|
532
|
+
flags_to_return: None | NDArray[np.bool] = None
|
|
526
533
|
|
|
527
|
-
#
|
|
534
|
+
# Set up the offsets. By default we will be tapering around the field,
|
|
535
|
+
# but should w_delays be specified these will be modified to direct
|
|
536
|
+
# towards the nominated object in the if below
|
|
528
537
|
tukey_x_offset: u.Quantity = np.zeros_like(delay_time.delay)
|
|
529
538
|
|
|
530
539
|
if w_delays is not None:
|
|
531
540
|
baseline_idx, time_idx = _get_baseline_time_indicies(
|
|
532
541
|
w_delays=w_delays, data_chunk=data_chunk
|
|
533
542
|
)
|
|
534
|
-
|
|
535
|
-
|
|
543
|
+
original_tukey_x_offset = w_delays.w_delays[baseline_idx, time_idx]
|
|
544
|
+
|
|
545
|
+
# Make a copy for later use post wrapping
|
|
546
|
+
tukey_x_offset = original_tukey_x_offset.copy()
|
|
547
|
+
|
|
548
|
+
tukey_x_offset = symmetric_domain_wrap(
|
|
549
|
+
values=tukey_x_offset.value, upper_limit=np.max(delay_time.delay).value
|
|
550
|
+
)
|
|
536
551
|
|
|
537
552
|
# need to scale the x offsert to the -pi to pi
|
|
538
553
|
# The delay should be symmetric
|
|
539
554
|
tukey_x_offset = (
|
|
540
555
|
tukey_x_offset / (np.max(delay_time.delay) / np.pi).decompose()
|
|
541
556
|
).value
|
|
542
|
-
# logger.info(f"{tukey_x_offset=}")
|
|
557
|
+
# # logger.info(f"{tukey_x_offset=}")
|
|
543
558
|
|
|
544
559
|
taper = tukey_taper(
|
|
545
560
|
x=delay_time.delay,
|
|
@@ -547,29 +562,70 @@ def _tukey_tractor(
|
|
|
547
562
|
tukey_width=tukey_tractor_options.tukey_width,
|
|
548
563
|
tukey_x_offset=tukey_x_offset,
|
|
549
564
|
)
|
|
550
|
-
|
|
565
|
+
|
|
566
|
+
if w_delays is None:
|
|
567
|
+
# This is the easy case
|
|
568
|
+
taper = taper[None, :, None]
|
|
569
|
+
|
|
570
|
+
else:
|
|
571
|
+
# TODO: This pirate reckons that merging the masks together
|
|
572
|
+
# into a single mask throughout may make things easier to
|
|
573
|
+
# manage and visualise.
|
|
574
|
+
|
|
551
575
|
# The use of the `tukey_x_offset` changes the
|
|
552
576
|
# shape of the output array. The internals of that
|
|
553
577
|
# function returns a different shape via the broadcasting
|
|
554
578
|
taper = np.swapaxes(taper[:, :, None], 0, 1)
|
|
555
579
|
|
|
556
|
-
# Since we want to dampen the target object we invert the taper
|
|
580
|
+
# Since we want to dampen the target object we invert the taper.
|
|
581
|
+
# By default the taper dampers outside the inner region.
|
|
557
582
|
taper = 1.0 - taper
|
|
558
583
|
|
|
584
|
+
# apply the flags to ignore the tapering if the object is larger
|
|
585
|
+
# than one wrap away
|
|
586
|
+
# Calculate the offset account of nyquist sampling
|
|
587
|
+
no_wraps_for_offset = calculate_nyquist_zone(
|
|
588
|
+
values=original_tukey_x_offset.value,
|
|
589
|
+
upper_limit=np.max(delay_time.delay).value,
|
|
590
|
+
)
|
|
591
|
+
ignore_wrapping_for = (
|
|
592
|
+
no_wraps_for_offset > tukey_tractor_options.ignore_nyquist_zone
|
|
593
|
+
)
|
|
594
|
+
taper[ignore_wrapping_for, :, :] = 1.0
|
|
595
|
+
|
|
559
596
|
# Delay with the elevation of the target object
|
|
560
|
-
# TODO: Allow elevation to be a user parameter
|
|
561
597
|
elevation_mask = w_delays.elevation < tukey_tractor_options.elevation_cut
|
|
562
598
|
taper[elevation_mask[time_idx], :, :] = 1.0
|
|
563
599
|
|
|
564
|
-
#
|
|
565
|
-
|
|
566
|
-
#
|
|
567
|
-
#
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
600
|
+
# Compute flags to ignore the objects delay crossing 0, Do
|
|
601
|
+
# This by computing the taper towards the field and
|
|
602
|
+
# see if there are any components of the two sets of tapers
|
|
603
|
+
# that are not 1 (where 1 is 'no change').
|
|
604
|
+
field_taper = tukey_taper(
|
|
605
|
+
x=delay_time.delay,
|
|
606
|
+
outer_width=tukey_tractor_options.outer_width / 4,
|
|
607
|
+
tukey_width=tukey_tractor_options.tukey_width,
|
|
608
|
+
tukey_x_offset=None,
|
|
609
|
+
)
|
|
610
|
+
# We need to account for no broadcasting when offset is None
|
|
611
|
+
# as the returned shape is different
|
|
612
|
+
field_taper = field_taper[None, :, None]
|
|
613
|
+
field_taper = 1.0 - field_taper
|
|
614
|
+
intersecting_taper = np.any(
|
|
615
|
+
np.reshape((taper != 1) & (field_taper != 1), (taper.shape[0], -1)), axis=1
|
|
616
|
+
)
|
|
617
|
+
# # Should the data need to be modified in conjunction with the flags
|
|
618
|
+
# taper[
|
|
619
|
+
# intersecting_taper &
|
|
620
|
+
# ~elevation_mask[time_idx] &
|
|
621
|
+
# ~ignore_wrapping_for
|
|
622
|
+
# ] = 0.0
|
|
623
|
+
# Update flags
|
|
624
|
+
flags_to_return = np.zeros_like(data_chunk.masked_data.mask)
|
|
625
|
+
flags_to_return[intersecting_taper] = True
|
|
626
|
+
flags_to_return = (
|
|
627
|
+
~np.isfinite(data_chunk.masked_data.filled(np.nan)) | flags_to_return
|
|
628
|
+
)
|
|
573
629
|
|
|
574
630
|
# Delay-time is a 3D array: (time, delay, pol)
|
|
575
631
|
# Taper is 1D: (delay,)
|
|
@@ -587,7 +643,7 @@ def _tukey_tractor(
|
|
|
587
643
|
)
|
|
588
644
|
logger.debug(f"{tapered_data.masked_data.shape=} {tapered_data.masked_data.dtype}")
|
|
589
645
|
|
|
590
|
-
return tapered_data
|
|
646
|
+
return tapered_data, flags_to_return
|
|
591
647
|
|
|
592
648
|
|
|
593
649
|
@dataclass
|
|
@@ -609,7 +665,7 @@ class TukeyTractorOptions:
|
|
|
609
665
|
dry_run: bool = False
|
|
610
666
|
"""Indicates whether the data will be written back to the measurement set"""
|
|
611
667
|
make_plots: bool = False
|
|
612
|
-
"""Create a small set of diagnostic plots"""
|
|
668
|
+
"""Create a small set of diagnostic plots. This can be slow."""
|
|
613
669
|
overwrite: bool = False
|
|
614
670
|
"""If the output column exists it will be overwritten"""
|
|
615
671
|
chunk_size: int = 1000
|
|
@@ -620,6 +676,8 @@ class TukeyTractorOptions:
|
|
|
620
676
|
"""The target object to apply the delay towards."""
|
|
621
677
|
elevation_cut: u.Quantity = -1 * u.deg
|
|
622
678
|
"""The elevation cut-off for the target object. Defaults to 0 degrees."""
|
|
679
|
+
ignore_nyquist_zone: int = 2
|
|
680
|
+
"""Do not apply the tukey taper if object is beyond this Nyquist zone"""
|
|
623
681
|
|
|
624
682
|
|
|
625
683
|
def tukey_tractor(
|
|
@@ -635,8 +693,10 @@ def tukey_tractor(
|
|
|
635
693
|
Args:
|
|
636
694
|
tukey_tractor_options (TukeyTractorOptions): The settings to use during the taper, and measurement set to apply them to.
|
|
637
695
|
"""
|
|
638
|
-
|
|
639
|
-
|
|
696
|
+
log_jolly_roger_version()
|
|
697
|
+
log_dataclass_attributes(
|
|
698
|
+
to_log=tukey_tractor_options, class_name="TukeyTaperOptions"
|
|
699
|
+
)
|
|
640
700
|
|
|
641
701
|
# acquire all the tables necessary to get unit information and data from
|
|
642
702
|
open_ms_tables = get_open_ms_tables(
|
|
@@ -671,7 +731,7 @@ def tukey_tractor(
|
|
|
671
731
|
chunk_size=tukey_tractor_options.chunk_size,
|
|
672
732
|
data_column=tukey_tractor_options.data_column,
|
|
673
733
|
):
|
|
674
|
-
taper_data_chunk = _tukey_tractor(
|
|
734
|
+
taper_data_chunk, flags_to_apply = _tukey_tractor(
|
|
675
735
|
data_chunk=data_chunk,
|
|
676
736
|
tukey_tractor_options=tukey_tractor_options,
|
|
677
737
|
w_delays=w_delays,
|
|
@@ -686,6 +746,13 @@ def tukey_tractor(
|
|
|
686
746
|
startrow=taper_data_chunk.row_start,
|
|
687
747
|
nrow=taper_data_chunk.chunk_size,
|
|
688
748
|
)
|
|
749
|
+
if flags_to_apply is not None:
|
|
750
|
+
open_ms_tables.main_table.putcol(
|
|
751
|
+
columnname="FLAG",
|
|
752
|
+
value=flags_to_apply,
|
|
753
|
+
startrow=taper_data_chunk.row_start,
|
|
754
|
+
nrow=taper_data_chunk.chunk_size,
|
|
755
|
+
)
|
|
689
756
|
|
|
690
757
|
if tukey_tractor_options.make_plots:
|
|
691
758
|
plot_paths = make_plot_results(
|
|
@@ -752,7 +819,7 @@ def get_parser() -> ArgumentParser:
|
|
|
752
819
|
tukey_parser.add_argument(
|
|
753
820
|
"--make-plots",
|
|
754
821
|
action="store_true",
|
|
755
|
-
help="If set, the Tukey tractor will make plots of the results",
|
|
822
|
+
help="If set, the Tukey tractor will make plots of the results. This can be slow.",
|
|
756
823
|
)
|
|
757
824
|
tukey_parser.add_argument(
|
|
758
825
|
"--overwrite",
|
|
@@ -776,6 +843,12 @@ def get_parser() -> ArgumentParser:
|
|
|
776
843
|
action="store_true",
|
|
777
844
|
help="Whether the tukey taper is applied towards the target object (e.g. the Sun). If not set, the taper is applied towards large delays.",
|
|
778
845
|
)
|
|
846
|
+
tukey_parser.add_argument(
|
|
847
|
+
"--ignore-nyquist-zone",
|
|
848
|
+
type=int,
|
|
849
|
+
default=2,
|
|
850
|
+
help="Do not apply the taper if the objects delays beyond this Nyquist zone",
|
|
851
|
+
)
|
|
779
852
|
|
|
780
853
|
return parser
|
|
781
854
|
|
|
@@ -799,7 +872,9 @@ def cli() -> None:
|
|
|
799
872
|
chunk_size=args.chunk_size,
|
|
800
873
|
target_object=args.target_object,
|
|
801
874
|
apply_towards_object=args.apply_towards_object,
|
|
875
|
+
ignore_nyquist_zone=args.ignore_nyquist_zone,
|
|
802
876
|
)
|
|
877
|
+
|
|
803
878
|
tukey_tractor(tukey_tractor_options=tukey_tractor_options)
|
|
804
879
|
else:
|
|
805
880
|
parser.print_help()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Small helper utility functions"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import is_dataclass
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from jolly_roger import __version__
|
|
9
|
+
from jolly_roger.logging import logger
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def log_jolly_roger_version() -> None:
|
|
13
|
+
"""Write out a jolly roger header to output"""
|
|
14
|
+
logger.info("Jolly-Roger: Flagging and Tapering")
|
|
15
|
+
logger.info(f"Version: {__version__}")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def log_dataclass_attributes(to_log: Any, class_name: str | None = None) -> None:
|
|
19
|
+
"""Log the attributes and values from an Dataclass"""
|
|
20
|
+
if not is_dataclass(to_log):
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
if class_name:
|
|
24
|
+
logger.info(f"Settings for {class_name}")
|
|
25
|
+
|
|
26
|
+
for attribute in to_log.__annotations__:
|
|
27
|
+
value = to_log.__dict__[attribute]
|
|
28
|
+
logger.info(f"{attribute:<30} = {value}")
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Helper utilities to deal with cyclic boundaries
|
|
2
|
+
on data"""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from numpy.typing import NDArray
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def symmetric_domain_wrap(
|
|
11
|
+
values: NDArray[np.floating], upper_limit: float
|
|
12
|
+
) -> NDArray[np.floating]:
|
|
13
|
+
"""Place a set of values into a cyclic domain that is
|
|
14
|
+
symmetric around zero.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
values (NDArray[np.floating]): Values that need to be mapped into the cyclic domain
|
|
18
|
+
upper_limit (float): The upper bound of the symmetric cyclic domain
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
NDArray[np.floating]: Values that have been mapped to the -upper_limit to upper_limit domain
|
|
22
|
+
"""
|
|
23
|
+
# Calculate an appropriate domain mapping
|
|
24
|
+
# The natural domain is going to be mapped
|
|
25
|
+
# to -pi to pi.
|
|
26
|
+
domain_mapping = np.pi / upper_limit
|
|
27
|
+
|
|
28
|
+
real = np.cos(values * domain_mapping)
|
|
29
|
+
imag = np.sin(values * domain_mapping)
|
|
30
|
+
|
|
31
|
+
wrapped_values = real + 1j * imag
|
|
32
|
+
|
|
33
|
+
return np.angle(wrapped_values) / domain_mapping
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def calculate_nyquist_zone(
|
|
37
|
+
values: NDArray[np.floating], upper_limit: float
|
|
38
|
+
) -> NDArray[np.int_]:
|
|
39
|
+
"""Return the nyquist zone a value is in for a symmetric
|
|
40
|
+
set of bounds around zero
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
values (NDArray[np.floating]): The values to calculate the zone for
|
|
44
|
+
upper_limit (float): The upper bound to the symmetric domain around zero
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
NDArray[np.int_]: The zones values correspond to
|
|
48
|
+
"""
|
|
49
|
+
return np.array(
|
|
50
|
+
np.floor((upper_limit + np.abs(values)) / (2.0 * upper_limit)) + 1, dtype=int
|
|
51
|
+
)
|
|
Binary file
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Tests to ensure correctness of the
|
|
2
|
+
wrapping utilities"""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from jolly_roger.wrap import calculate_nyquist_zone, symmetric_domain_wrap
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_symmetric_domain_wrap_with_2d_arrays() -> None:
|
|
12
|
+
"""Ensure mapping values to a periodic domain works for arrays"""
|
|
13
|
+
|
|
14
|
+
values = np.array([np.linspace(10, 40, 10), np.linspace(10, 40, 10)])
|
|
15
|
+
assert values.shape == (2, 10)
|
|
16
|
+
|
|
17
|
+
wrapped_values = symmetric_domain_wrap(values=values, upper_limit=60)
|
|
18
|
+
assert wrapped_values.shape == values.shape
|
|
19
|
+
assert np.all(np.isclose(wrapped_values, values))
|
|
20
|
+
|
|
21
|
+
# The addition of 120 is the size of the domain here
|
|
22
|
+
# and they should be wrapped back to the main map
|
|
23
|
+
larger_values = np.array(
|
|
24
|
+
[np.linspace(10, 40, 10), np.linspace(10 + 120, 40 + 120, 10)]
|
|
25
|
+
)
|
|
26
|
+
assert values.shape == (2, 10)
|
|
27
|
+
|
|
28
|
+
wrapped_values = symmetric_domain_wrap(values=larger_values, upper_limit=60)
|
|
29
|
+
assert wrapped_values.shape == values.shape
|
|
30
|
+
assert np.all(np.isclose(wrapped_values, values))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_symmetric_domain_wrap() -> None:
|
|
34
|
+
"""Ensure mapping values to a periodic domain works"""
|
|
35
|
+
|
|
36
|
+
values = np.linspace(10, 40, 10)
|
|
37
|
+
|
|
38
|
+
wrapped_values = symmetric_domain_wrap(values=values, upper_limit=60)
|
|
39
|
+
assert np.all(np.isclose(values, wrapped_values))
|
|
40
|
+
|
|
41
|
+
values = np.linspace(10, 40, 10)
|
|
42
|
+
|
|
43
|
+
# Domain size would be 120 values given the upper limit of 60
|
|
44
|
+
wrapped_values = symmetric_domain_wrap(values=values + 120, upper_limit=60)
|
|
45
|
+
assert np.all(np.isclose(values, wrapped_values))
|
|
46
|
+
|
|
47
|
+
values = np.linspace(10, 40, 10)
|
|
48
|
+
|
|
49
|
+
# Domain size would be 120 values given the upper limit of 60
|
|
50
|
+
wrapped_values = symmetric_domain_wrap(values=values + 2 * 120, upper_limit=60)
|
|
51
|
+
assert np.all(np.isclose(values, wrapped_values))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_calculate_nyquist_zone() -> None:
|
|
55
|
+
"""Match to the right zone"""
|
|
56
|
+
assert calculate_nyquist_zone(values=30, upper_limit=60) == 1
|
|
57
|
+
assert calculate_nyquist_zone(values=90, upper_limit=60) == 2
|
|
58
|
+
assert calculate_nyquist_zone(values=-30, upper_limit=60) == 1
|
|
59
|
+
assert calculate_nyquist_zone(values=-90, upper_limit=60) == 2
|
|
60
|
+
|
|
61
|
+
assert np.all(
|
|
62
|
+
calculate_nyquist_zone(values=np.array([-90, -30, 0, 30, 90]), upper_limit=60)
|
|
63
|
+
== np.array([2, 1, 1, 1, 2])
|
|
64
|
+
)
|
|
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
|