Skip to content

Commit

Permalink
Merge pull request #305 from HERA-Team/np-upgrade
Browse files Browse the repository at this point in the history
fix: import blackmanharris from scipy.signal.windows
  • Loading branch information
steven-murray authored Apr 23, 2024
2 parents 64c7a3a + 921110a commit 47b4f0f
Show file tree
Hide file tree
Showing 19 changed files with 184 additions and 59 deletions.
2 changes: 2 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ ignore =
G004,
# Logging statement uses + (this makes no sense...)
G003,
# Allow builtin module names
A005,
max-line-length = 88
# Should be 18.
max-complexity = 35
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test_suite.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
python-version: [3.9, "3.10", "3.11"]
python-version: ["3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@main
Expand Down
17 changes: 12 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ exclude: 'config.yaml|config_examples/.*.yaml|hera_sim/config/H1C.yaml|hera_sim/

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: check-added-large-files
Expand All @@ -25,7 +25,6 @@ repos:
- flake8-rst-docstrings
#- flake8-docstrings # not available for flake8>5
- flake8-builtins
- flake8-logging-format
- flake8-rst-docstrings
- flake8-rst
# - flake8-markdown # not available for flake8>5 (check later...)
Expand All @@ -34,7 +33,7 @@ repos:
- flake8-print

- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.2.0
rev: 24.4.0
hooks:
- id: black

Expand All @@ -49,12 +48,20 @@ repos:
- id: isort

- repo: https://github.com/asottile/pyupgrade
rev: v3.15.1
rev: v3.15.2
hooks:
- id: pyupgrade
args: [--py39-plus]

- repo: https://github.com/asottile/setup-cfg-fmt
rev: v2.5.0
hooks:
- id: setup-cfg-fmt
- id: setup-cfg-fmt

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.4.1
hooks:
# Run the linter.
- id: ruff
args: [--fix]
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ Changelog
dev
===

Deprecated
----------

- Support for Python 3.9 has been dropped.

Fixed
-----
- API calls for pyuvdata v2.4.0.
Expand Down
4 changes: 2 additions & 2 deletions hera_sim/cli_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def validate_config(config: dict):
is not valid.
"""
if config.get("defaults") is not None:
if type(config["defaults"]) is not str:
if not isinstance(config["defaults"], str):
raise ValueError(
"Defaults in the CLI may only be specified using a string. "
"The string used may specify either a path to a configuration "
Expand Down Expand Up @@ -155,7 +155,7 @@ def write_calfits(
# Update gain keys to conform to write_cal assumptions.
# New Simulator gains have keys (ant, pol), so shouldn't need
# special pre-processing.
if all(np.issctype(type(ant)) for ant in gains.keys()):
if all(np.isscalar(ant) for ant in gains.keys()):
# Old-style, single polarization assumption.
gains = {(ant, "Jee"): gain for ant, gain in gains.items()}

Expand Down
7 changes: 5 additions & 2 deletions hera_sim/data/tutorials_data/end_to_end/make_mock_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ def make_mock_catalog(
sigma=5,
index_low=-3,
index_high=-1,
seed=None,
):
"""Generate and svae a mock point source catalog."""
# Easiset to load the metadata this way.
rng = np.random.default_rng(seed)

temp_uvdata = initialize_uvdata_from_params(str(obsparam_file))[0]
center_time = np.mean(np.unique(temp_uvdata.time_array))
ref_freq = np.mean(np.unique(temp_uvdata.freq_array))
Expand All @@ -38,11 +41,11 @@ def make_mock_catalog(
decs = np.array([row[2] for row in sky_model_recarray])

# Randomly assign fluxes (whether this is realistic or not).
ref_fluxes = np.random.lognormal(mean=1, sigma=sigma, size=len(ras))
ref_fluxes = rng.lognormal(mean=1, sigma=sigma, size=len(ras))
# Don't include super bright sources.
ref_fluxes[ref_fluxes > flux_cut] = 1 / ref_fluxes[ref_fluxes > flux_cut]
# Assign spectral indices.
indices = np.random.uniform(low=index_low, high=index_high, size=len(ras))
indices = rng.uniform(low=index_low, high=index_high, size=len(ras))

# Actually add in the spectral structure.
freqs = np.unique(temp_uvdata.freq_array)
Expand Down
4 changes: 2 additions & 2 deletions hera_sim/interpolators.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,8 @@ def _check_format(self):
)
assert self._obj in self._data.keys() and "freqs" in self._data.keys(), (
"You've chosen to use an interp1d object for modeling the "
"{}. Please ensure that the `.npz` archive has the following "
"keys: 'freqs', '{}'".format(self._obj, self._obj)
f"{self._obj}. Please ensure that the `.npz` archive has the following "
f"keys: 'freqs', '{self._obj}'"
)
else:
# we can relax this a bit and allow for users to also pass a npz
Expand Down
4 changes: 2 additions & 2 deletions hera_sim/rfi.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,8 +484,8 @@ def _listify_params(self, bands, *args):
"values with the same length as the number of DTV "
"bands specified. For reference, the DTV bands you "
"specified have the following characteristics: \n"
"f_min : {fmin} \nf_max : {fmax}\n N_bands : "
"{Nchan}".format(fmin=bands[0], fmax=bands[-1], Nchan=Nchan)
f"f_min : {bands[0]} \nf_max : {bands[-1]}\n N_bands : "
f"{Nchan}"
)

# everything should be in order now, so
Expand Down
2 changes: 1 addition & 1 deletion hera_sim/sigchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from pyuvdata import UVBeam
from pyuvsim import AnalyticBeam
from scipy import stats
from scipy.signal import blackmanharris
from scipy.signal.windows import blackmanharris
from typing import Callable

from . import DATA_PATH, interpolators, utils
Expand Down
72 changes: 53 additions & 19 deletions hera_sim/simulate.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:class:`Simulator`, please refer to the tutorials.
"""

import contextlib
import functools
import inspect
import numpy as np
Expand All @@ -18,6 +19,7 @@
from deprecation import deprecated
from pathlib import Path
from pyuvdata import UVData
from pyuvdata import utils as uvutils
from typing import Optional, Union

from . import __version__, io, utils
Expand Down Expand Up @@ -727,7 +729,7 @@ def _apply_filter(vis_filter, ant1, ant2, pol):
return not pol == vis_filter[0]
# Otherwise, assume that this specifies an antenna.
else:
return not vis_filter[0] in (ant1, ant2)
return vis_filter[0] not in (ant1, ant2)
elif len(vis_filter) == 2:
# TODO: This will need to be updated when we support ant strings.
# Three cases: two pols; an ant+pol; a baseline.
Expand Down Expand Up @@ -756,7 +758,7 @@ def _apply_filter(vis_filter, ant1, ant2, pol):
for key in vis_filter:
if isinstance(key, str):
pols.append(key)
elif type(key) is int:
elif isinstance(key, int):
ants.append(key)
# We want polarization and ant1 or ant2 in the filter.
# This would be used in simulating e.g. a few feeds that have an
Expand Down Expand Up @@ -1228,7 +1230,7 @@ def _seed_rng(self, seed, model, ant1=None, ant2=None, pol=None):
"""
if seed is None:
return
if type(seed) is int:
if isinstance(seed, int):
np.random.seed(seed)
return seed
if not isinstance(seed, str):
Expand Down Expand Up @@ -1390,9 +1392,7 @@ def _get_component(
component: Union[str, type[SimulationComponent], SimulationComponent]
) -> Union[SimulationComponent, type[SimulationComponent]]:
"""Normalize a component to be either a class or instance."""
if np.issubclass_(component, SimulationComponent):
return component
elif isinstance(component, str):
if isinstance(component, str):
try:
return get_model(component)
except KeyError:
Expand All @@ -1403,6 +1403,9 @@ def _get_component(
elif isinstance(component, SimulationComponent):
return component
else:
with contextlib.suppress(TypeError):
if issubclass(component, SimulationComponent):
return component
raise TypeError(
"The input type for the component was not understood. "
"Must be a string, or a class/instance of type 'SimulationComponent'. "
Expand Down Expand Up @@ -1435,11 +1438,13 @@ def _get_model_name(model):
"""Find out the (lowercase) name of a provided model."""
if isinstance(model, str):
return model.lower()
elif np.issubclass_(model, SimulationComponent):
return model.__name__.lower()
elif isinstance(model, SimulationComponent):
return model.__class__.__name__.lower()
else:
with contextlib.suppress(TypeError):
if issubclass(model, SimulationComponent):
return model.__name__.lower()

raise TypeError(
"You are trying to simulate an effect using a custom function. "
"Please refer to the tutorial for instructions regarding how "
Expand All @@ -1448,6 +1453,28 @@ def _get_model_name(model):

def _parse_key(self, key: Union[int, str, AntPair, AntPairPol]) -> AntPairPol:
"""Convert a key of at-most length-3 to an (ant1, ant2, pol) tuple."""
valid_pols = {
k.lower()
for k in {
**uvutils.POL_STR2NUM_DICT,
**uvutils.JONES_STR2NUM_DICT,
**uvutils.CONJ_POL_DICT,
}
}
valid_pols.update({"jee", "jen", "jne", "jnn"})

def checkpol(pol):
if pol is None:
return None

if not isinstance(pol, str):
raise TypeError(f"Invalid polarization type: {type(pol)}.")

if pol.lower() not in valid_pols:
raise ValueError(f"Invalid polarization string: {pol}.")

return pol

if key is None:
ant1, ant2, pol = None, None, None
elif np.issubdtype(type(key), int):
Expand All @@ -1460,26 +1487,33 @@ def _parse_key(self, key: Union[int, str, AntPair, AntPairPol]) -> AntPairPol:
elif isinstance(key, str):
if key.lower() in ("auto", "cross"):
raise NotImplementedError("Functionality not yet supported.")
key = checkpol(key)
ant1, ant2, pol = None, None, key
else:

def intify(x):
return x if x is None else int(x)

try:
iter(key)
iter(key) # ensure it's iterable
if len(key) not in (2, 3):
raise TypeError

if len(key) == 2:
if all(isinstance(val, int) for val in key):
ant1, ant2 = key
pol = None
else:
ant1, pol = intify(key[0]), checkpol(key[1])
ant2 = None
else:
ant1, ant2, pol = intify(key[0]), intify(key[1]), checkpol(key[2])

except TypeError:
raise ValueError(
"Key must be an integer, string, antenna pair, or antenna "
"pair with a polarization string."
f"pair with a polarization string. Got {key}."
)
if len(key) == 2:
if all(type(val) is int for val in key):
ant1, ant2 = key
pol = None
else:
ant1, pol = key
ant2 = None
else:
ant1, ant2, pol = key
return ant1, ant2, pol

def _sanity_check(self, model):
Expand Down
4 changes: 2 additions & 2 deletions hera_sim/tests/test_sim_red_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ def test_sim_red_data_4pol(antpos, gain_data):
for pol in ["xx", "xy", "yx", "yy"]:
ai, aj, pol = bl0
ans0 = data[ai, aj, pol] / (
gains[(ai, f"J{pol[0]*2}")] * gains[(aj, f"J{pol[1]*2}")].conj()
gains[(ai, f"J{pol[0] * 2}")] * gains[(aj, f"J{pol[1] * 2}")].conj()
)

for bl in bls[1:]:
ai, aj, pol = bl
ans = data[ai, aj, pol] / (
gains[(ai, f"J{pol[0]*2}")] * gains[(aj, f"J{pol[1]*2}")].conj()
gains[(ai, f"J{pol[0] * 2}")] * gains[(aj, f"J{pol[1] * 2}")].conj()
)

# compare calibrated visibilities knowing the input gains
Expand Down
Loading

0 comments on commit 47b4f0f

Please sign in to comment.