Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: allow external beams (plus some minor things) #43

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

hughbg
Copy link

@hughbg hughbg commented Feb 25, 2021

This pull request contains a few minor changes and one significant change. All the changes are backwards compatible. I’ve run all the tests in the tests/ directory and they all pass. I’ve added another test script.

The minor changes are:

  • Allow a random seed to be passed to construct_skymodel(), which then calls np.random.seed(seed). This means that a “flat_spec” sky model is repeatable.
  • Allow a telescope height to be specified, along with latitude/longitude.
  • Ignore sources below the horizon when calculating a beam value. This probably should be handled by “horizon_taper” but it is turned off. I added a simple statement that zeros pixels below the horizon, but doesn’t take pixel area into account. I needed to do this because I was using a beam that goes below the horizon.

The significant change is to allow the use of external beams derived from and including pyuvsim AnalyticBeam. We (Phil Bull’s group) want to use the Fagnoni-type beams that have been developed for hera_sim: https://github.com/HERA-Team/hera_sim/blob/polybeam/hera_sim/beams.py. The beams do not need to be the same for all antennas, and are passed as a list to set_beam(). UVBeam objects could also be used, but UVBeam has a lot of other parameters which I have not implemented, and also are not implemented by pyuvsim AnalyticBeam. All these beams probably need a consistent interface.

There is a slight issue with this enhancement because the beams defined within healvis (healvis AnalyticBeam) are baseline beams, but the external beams are antenna beams. Antenna beams for a baseline must be multiplied when generating visibilities. Code has been added to keep track of per-antenna beams and then multiply beams when visibilities are calculated in _vis_calc().

@hughbg
Copy link
Author

hughbg commented Feb 26, 2021

My test script is failing because it imports a couple of packages that are not available. I can work around that and will push an update.

@codecov
Copy link

codecov bot commented Feb 26, 2021

Codecov Report

Merging #43 (9c9105c) into master (9c17ef4) will increase coverage by 0.45%.
The diff coverage is 98.79%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #43      +/-   ##
==========================================
+ Coverage   88.74%   89.19%   +0.45%     
==========================================
  Files          16       18       +2     
  Lines        1661     1749      +88     
==========================================
+ Hits         1474     1560      +86     
- Misses        187      189       +2     
Impacted Files Coverage Δ
healvis/observatory.py 91.40% <97.43%> (+0.82%) ⬆️
healvis/sky_model.py 83.64% <100.00%> (+0.54%) ⬆️
healvis/tests/test_external_beam.py 100.00% <100.00%> (ø)
healvis/__init__.py 85.71% <0.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9c17ef4...9c9105c. Read the comment docs.

Copy link
Collaborator

@aelanman aelanman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @hughbg . Sorry I didn't see this sooner!

Thank you for adding this useful feature!

One minor issue I have is that the term "external beam" isn't very clear. It looks like this means "antenna beams" as defined in pyuvdata/sim. It's up to you, but calling it something else and adding some documentation what sort of interp function is expected would be helpful.

My main concern right now is that it still accepts the beam_pol keyword but doesn't use it if you're using antenna beams. As you can see in pyuvdata, the "polarizations" of a power beam are the various cross-pol terms, while for an E-field beam there are only different feeds to choose from.


Returns:
SkyModel object
"""

if seed is not None: np.random.seed(seed)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For style's sake, this should be two lines.

str: If it is a viable input to AnalyticBeam,
then instantiates an AnalyticBeam, otherwise assumes beam is
a filepath to a beamfits and instantiates a PowerBeam.
list: List of beam objects. This allows for external beams to be
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of the term "external" beam here. I think what you mean are the beam classes defined in pyuvdata and pyuvsim?

Since they're treated as antenna beams, it might be better to refer to them as such.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change to antenna beams. We've been using pyuvsim AnalyticBeam but mostly the new PolyBeam types in hera_sim that are derived from AnalyticBeam.


if isinstance(beam, list): self.beam = beam
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If statements should be multi-line.

It also might be good to check here that the beam object has an interp method.

beam_val[i] = bv
for bi, bl in enumerate(self.array):
# Multiply beam correction for the two antennas in each baseline
beam_cube[bi] = beam_val[bl.ant1]*beam_val[bl.ant2]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't one be complex-conjugated? Please ignore if I'm wrong about that.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I should fix that. All the beams we've used so far return real values but in general they could be complex.

"""
interp_data, interp_basis_vector = beam.interp(az_array=az_arr, za_array=za_arr,
freq_array=freqs)
return interp_data[0, 0, 1].T # just want Npix, Nfreq
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like "pol" isn't used. I don't remember what the interp_data axes are offhand, but you should be careful that the correct polarization is being returned.

Part of the complication with supporting E-field beams it that you have to make sure you're extracting the right feed pair. I suppose the way to do this is (as with the existing code) only support on-diagonal components (XX and YY), and then the "beam_pol" option should be either X or Y.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check over this. I haven't been quite sure about the handling of polarization in the sim packages - if they're all doing the same thing or meant to be. Phil is adding polarization to hera_sim so he's grappling with this as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants