-
Notifications
You must be signed in to change notification settings - Fork 5
feat: Issue #48 feature 1 #49
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
Open
DanielaBreitman
wants to merge
38
commits into
main
Choose a base branch
from
better_lc_noise
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 20 commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
1fb3909
feat: Issue #48 feature 1
DanielaBreitman 1ad06be
feat: Issue #48 feature 1
DanielaBreitman 872bb40
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 6317d88
feat: Issue #48 feature 2
DanielaBreitman 7e847d7
feat: Issue #48 feature 2
DanielaBreitman 446ad62
feat: Issue #48 feature 2
DanielaBreitman fb1c5c1
feat: Issue #48 feature 2
DanielaBreitman 05055b9
feat: Issue #48 feature 2
DanielaBreitman 71c791a
feat: Issue #48 feature 2
DanielaBreitman 3dde869
feat: Issue #48 feature 2
DanielaBreitman 81becd3
feat: Issue #48 feature 2
DanielaBreitman ae21b85
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 65e9816
feat: Issue #48 feature 2
DanielaBreitman 1131f98
maint: fix tests
DanielaBreitman 149c253
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 6b4fec4
feat: Issue #48 finish fnc 1
DanielaBreitman 76d1a4e
feat: Issue #48 finish fnc 2
DanielaBreitman 2766259
maint: fix tests
DanielaBreitman 028bf5d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 6a9046e
maint: fix tests
DanielaBreitman 19e6565
maint: fix Steven's comments
DanielaBreitman 26e479f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] e7e1c84
fix: wedge removal done properly
DanielaBreitman ad98158
doc: can provide either beam area or Aeff
DanielaBreitman 8fcc95f
doc: can provide either beam area or Aeff
DanielaBreitman 1fb7b8e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 66643bc
fix: wedge removal done properly
DanielaBreitman f737e0b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 9193db0
fix: wedge removal NOT done properly
DanielaBreitman 9fcd546
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 12bb69d
refactor: change some function names and make lightcone obs more clear
steven-murray fddae9a
maint: ignore ipynb checkpoints
steven-murray d845955
feat: add ability to apply spatial taper again
steven-murray 3ccaaf9
remove checkpoint files
steven-murray 46c146e
fix: scaling of uv grid and conjugate halving
steven-murray 57ba8ff
feat: add ability to do inv variance weighting in map-making
steven-murray b6ae16f
fix: correct uv gridding
steven-murray b0cf2a9
style: run ruff
steven-murray File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,8 +17,8 @@ | |
| def grid_baselines_uv( | ||
| uvws: np.ndarray, | ||
| freq: un.Quantity, | ||
| boxlength: un.Quantity, | ||
| lc_shape: tuple[int, int, int], | ||
| boxlen: un.Quantity, | ||
| boxnside: int, | ||
| weights: np.ndarray, | ||
| include_mirrored_bls: bool = True, | ||
| avg_mirrored_bls: bool = True, | ||
|
|
@@ -31,12 +31,10 @@ def grid_baselines_uv( | |
| Baselines in uv space with shape (N bls, N time offsets, 3). | ||
| freq : un.Quantity | ||
| Frequency at which the baselines are projected. | ||
| boxlength : un.Quantity | ||
| boxlen : un.Quantity | ||
| Transverse length of the simulation box. | ||
| lc_shape : tuple | ||
| Shape of the lightcone (Nx, Ny, Nz). | ||
| We assume that Nx = Ny to be sky-plane dimensions, | ||
| and Nz to be to line-of-sight (frequency) dimension. | ||
| boxnside : int | ||
| Number of bins Nx = Ny of a lightcone or coeval box. | ||
DanielaBreitman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| weights : np.ndarray | ||
| Weights for each baseline group with shape (N bls). | ||
| include_mirrored_bls : bool, optional | ||
|
|
@@ -55,13 +53,13 @@ def grid_baselines_uv( | |
| of observation with shape (Nu=Nx, Nv=Nx). | ||
|
|
||
| """ | ||
| if "littleh" in boxlength.unit.to_string(): | ||
| boxlength = boxlength.to(un.Mpc / littleh) | ||
| if "littleh" in boxlen.unit.to_string(): | ||
| boxlen = boxlen.to(un.Mpc / littleh) | ||
| else: | ||
| boxlength = boxlength.to(un.Mpc) * Planck18.h / littleh | ||
| dx = float(boxlength.value) / float(lc_shape[0]) | ||
| boxlen = boxlen.to(un.Mpc) * Planck18.h / littleh | ||
| dx = float(boxlen.value) / float(boxnside) | ||
| ugrid_edges = ( | ||
| np.fft.fftshift(np.fft.fftfreq(lc_shape[0], d=dx)) * 2 * np.pi * boxlength.unit | ||
| np.fft.fftshift(np.fft.fftfreq(boxnside, d=dx)) * 2 * np.pi * boxlen.unit | ||
| ) | ||
|
|
||
| du = ugrid_edges[1] - ugrid_edges[0] | ||
|
|
@@ -87,7 +85,7 @@ def thermal_noise_per_voxel( | |
| observation: Observation, | ||
| freqs: np.ndarray, | ||
| boxlen: float, | ||
| lc_shape: tuple[int, int, int], | ||
| boxnside: int, | ||
DanielaBreitman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| antenna_effective_area: un.Quantity | None = None, | ||
| beam_area: un.Quantity | None = None, | ||
| ): | ||
|
|
@@ -107,10 +105,8 @@ def thermal_noise_per_voxel( | |
| Frequencies at which the noise is calculated. | ||
| boxlen : astropy.units.Quantity | ||
| Transverse length of the simulation box. | ||
| lc_shape : tuple | ||
| Shape of the lightcone (Nx, Ny, Nz). | ||
| We assume that Nx = Ny to be sky-plane dimensions, | ||
| and Nz to be to line-of-sight (frequency) dimension. | ||
| boxnside : int | ||
| Number of bins Nx = Ny of a lightcone or coeval box. | ||
| antenna_effective_area : astropy.units.Quantity, optional | ||
| Effective area of the antenna with shape (Nfreqs,). | ||
| beam_area : astropy.units.Quantity, optional | ||
|
|
@@ -168,7 +164,7 @@ def thermal_noise_per_voxel( | |
|
|
||
| d = Planck18.comoving_distance(f2z(nu)).to(un.Mpc) # Mpc | ||
| theta_box = (boxlen.to(un.Mpc) / d) * un.rad | ||
| omega_pix = theta_box**2 / np.prod(lc_shape[:2]) | ||
| omega_pix = theta_box**2 / boxnside**2 | ||
|
|
||
| sqrt = np.sqrt(2.0 * observation.bandwidth.to("Hz") * obs.integration_time).to( | ||
| un.dimensionless_unscaled | ||
|
|
@@ -211,23 +207,30 @@ def sample_from_rms_noise( | |
| seed: int | None = None, | ||
| nsamples: int = 1, | ||
| window_fnc: str = "blackmanharris", | ||
| return_in_uv: bool = False, | ||
| ): | ||
| """Sample noise for a lightcone slice given the corresponding rms noise in uv space. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| rms_noise : astropy.units.Quantity | ||
| RMS noise in uv space, shape (Nx, Ny, Nfreqs). | ||
| seed : int, optional | ||
| Random seed for reproducibility, by default None. | ||
| nsamples : int, optional | ||
| Number of noise realisations to sample, by default 1. | ||
| window_fnc : str, optional | ||
| Name of window function to be applied to the noise sampled in uv space, | ||
| by default windows.blackmanharris. | ||
| return_in_uv : bool, optional | ||
| If True, return the noise sampled in uv space instead of real space, | ||
| by default False. | ||
|
|
||
| Returns | ||
| ------- | ||
| lc_noise : un.Quantity | ||
| Noise sampled in real space, shape (nsamples, Nx, Ny, Nfreqs | ||
| noise : un.Quantity | ||
| Noise sampled in real or uv space, shape | ||
| (nsamples, Nx or Nu, Ny or Nv, Nfreqs) | ||
|
|
||
| """ | ||
| if len(rms_noise.shape) == 2: | ||
|
|
@@ -246,23 +249,53 @@ def sample_from_rms_noise( | |
|
|
||
| noise *= window_fnc[None, ..., None] | ||
| noise = (noise + np.conj(noise)) / 2.0 | ||
| noise = np.fft.ifft2(np.fft.ifftshift(noise, axes=(1, 2)), axes=(1, 2)) | ||
| noise = np.fft.ifftshift(noise, axes=(1, 2)) | ||
| if not return_in_uv: | ||
| noise = np.fft.ifft2(noise, axes=(1, 2)).real * rms_noise.unit | ||
| else: | ||
| noise = noise * rms_noise.unit | ||
|
|
||
| return noise.real * rms_noise.unit | ||
| return noise | ||
|
|
||
|
|
||
| def sample_lc_noise( | ||
| def thermal_noise_uv( | ||
| observation: Observation, | ||
| freqs: un.Quantity, | ||
| boxlength: un.Quantity, | ||
| lc_shape: tuple[int, int, int], | ||
| boxlen: un.Quantity, | ||
| boxnside: int, | ||
DanielaBreitman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| antenna_effective_area: un.Quantity | None = None, | ||
| beam_area: un.Quantity | None = None, | ||
| seed: int | None = None, | ||
| nsamples: int = 1, | ||
| window_fnc: str = "blackmanharris", | ||
| min_nbls_per_uv_cell: int = 1, | ||
| ): | ||
| """Test the grid_baselines function.""" | ||
| """Thermal noise RMS per voxel in uv space. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| observation : py21cmsense.Observation | ||
| Instance of `Observation`. | ||
| freqs : astropy.units.Quantity | ||
| Frequencies at which the noise is calculated. | ||
| boxlen : astropy.units.Quantity | ||
| Length of the box in which the noise is calculated. | ||
| boxnside : int | ||
| Number of bins Nx = Ny of a lightcone or coeval box. | ||
| antenna_effective_area : astropy.units.Quantity, optional | ||
| Effective area of the antenna with shape (Nfreqs,). | ||
| beam_area : astropy.units.Quantity, optional | ||
| Beam area of the antenna with shape (Nfreqs,). | ||
DanielaBreitman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| min_nbls_per_uv_cell : int, optional | ||
| Minimum number of baselines per uv cell to consider | ||
| the cell to be measured, by default 1. | ||
| sigma is set to zero for uv cells with less than | ||
| this number of baselines. | ||
|
||
|
|
||
| Returns | ||
| ------- | ||
| sigma : astropy.units.Quantity | ||
| Thermal noise RMS per voxel in uv space | ||
| with shape (Nx, Ny, Nfreqs). | ||
|
|
||
| """ | ||
| observatory = observation.observatory | ||
| time_offsets = observatory.time_offsets_from_obs_int_time( | ||
| observation.integration_time, observation.time_per_day | ||
|
|
@@ -276,24 +309,129 @@ def sample_lc_noise( | |
| baselines=baselines, time_offset=time_offsets | ||
| ) | ||
|
|
||
| uv_coverage = np.zeros((lc_shape[0], lc_shape[0], len(freqs))) | ||
| uv_coverage = np.zeros((boxnside, boxnside, len(freqs))) | ||
|
|
||
| for i, freq in enumerate(freqs): | ||
| uv_coverage[..., i] += grid_baselines_uv( | ||
| proj_bls[::2] * freq / freqs[0], freq, boxlength, lc_shape, weights[::2] | ||
| proj_bls[::2] * freq / freqs[0], freq, boxlen, boxnside, weights[::2] | ||
DanielaBreitman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ) | ||
|
|
||
| sigma_rms = thermal_noise_per_voxel( | ||
| observation, | ||
| freqs, | ||
| boxlength, | ||
| lc_shape, | ||
| boxlen, | ||
| boxnside, | ||
| antenna_effective_area=antenna_effective_area, | ||
| beam_area=beam_area, | ||
| ) | ||
| sigma = sigma_rms / np.sqrt(uv_coverage * observation.n_days) | ||
| sigma[uv_coverage == 0.0] = 0.0 | ||
| sigma[uv_coverage < min_nbls_per_uv_cell] = 0.0 | ||
| return sigma | ||
|
|
||
|
|
||
| def sample_lc_noise( | ||
| lightcone: un.Quantity, | ||
| observation: Observation, | ||
| boxlen: un.Quantity, | ||
| *, | ||
| freqs: un.Quantity | None = None, | ||
| lightcone_redshifts: float | None = None, | ||
| antenna_effective_area: un.Quantity | None = None, | ||
| beam_area: un.Quantity | None = None, | ||
| seed: int | None = None, | ||
| nsamples: int = 1, | ||
| window_fnc: str = "blackmanharris", | ||
| min_nbls_per_uv_cell: int = 1, | ||
| wedge_mu_min: float = 0.0, | ||
| ): | ||
| """Sample thermal noise and add it to a lightcone in Fourier space. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| lightcone : astropy.units.Quantity | ||
| Lightcone slice with shape (Nx, Ny, Nz). | ||
| observation : py21cmsense.Observation | ||
| Instance of `Observation`. | ||
| boxlen : astropy.units.Quantity | ||
| Length of the lightcone box side. | ||
| freqs : astropy.units.Quantity, optional | ||
| Frequencies at which the thermal noise is calculated. | ||
| Must have the same length as the lightcone frequency axis. | ||
| If not provided, freqs are calculated from lightcone_redshifts. | ||
| antenna_effective_area : astropy.units.Quantity, optional | ||
| Effective area of the antenna with shape (Nfreqs,). | ||
| beam_area : astropy.units.Quantity, optional | ||
| Beam area of the antenna with shape (Nfreqs,). | ||
| nsamples : int, optional | ||
| Number of noise realisations to sample, by default 1. | ||
| seed : int, optional | ||
| Random seed for reproducibility, by default None. | ||
| window_fnc : str, optional | ||
| Name of window function to be applied to the noise sampled in uv space, | ||
| by default windows.blackmanharris. | ||
| min_nbls_per_uv_cell : int, optional | ||
| Minimum number of baselines per uv cell to consider | ||
| the cell to be measured, by default 1. | ||
| Thermal noise in uv space is set to zero for | ||
| uv cells with less than this number of baselines. | ||
| wedge_mu_min : float, optional | ||
| Minimum cosine of the angle between the line of sight | ||
| and the k vector to consider a mode to be uncontaminated | ||
| by foregrounds, by default 0.0. | ||
|
|
||
| return sample_from_rms_noise( | ||
| sigma, seed=seed, nsamples=nsamples, window_fnc=window_fnc | ||
| Returns | ||
| ------- | ||
| lightcone samples with noise | ||
| """ | ||
| if freqs is None: | ||
| if lightcone_redshifts is None: | ||
| raise ValueError("You must provide either freqs or lightcone_redshifts.") | ||
| freqs = (1420.0 / (1 + lightcone_redshifts)) * un.MHz | ||
| if len(freqs) != lightcone.shape[2]: | ||
| raise ValueError( | ||
| "The length of freqs must be the same as the " | ||
| "length of the lightcone frequency axis." | ||
| ) | ||
| if type(wedge_mu_min) in [float, int]: | ||
| wedge_mu_min = np.zeros(len(freqs)) + wedge_mu_min | ||
| if np.min(wedge_mu_min) < 0 or np.max(wedge_mu_min) > 1: | ||
| raise ValueError("wedge_mu_min must be between 0 and 1.") | ||
DanielaBreitman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| sigma = thermal_noise_uv( | ||
| observation, | ||
| freqs, | ||
| boxlen, | ||
| lightcone.shape[0], | ||
| antenna_effective_area=antenna_effective_area, | ||
| beam_area=beam_area, | ||
| min_nbls_per_uv_cell=min_nbls_per_uv_cell, | ||
| ) | ||
DanielaBreitman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| sigma_noise_ft = sample_from_rms_noise( | ||
DanielaBreitman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| sigma, | ||
| seed=seed, | ||
| nsamples=nsamples, | ||
| window_fnc=window_fnc, | ||
| return_in_uv=True, | ||
| ) | ||
| lightcone -= lightcone.mean() | ||
DanielaBreitman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| lc_ft = np.fft.fft2(lightcone.value) * lightcone.unit | ||
| lc_ft[sigma == 0] = 0.0 | ||
| noisy_lc_ft = lc_ft + sigma_noise_ft | ||
| noisy_lc_ft[..., sigma == 0] = 0.0 | ||
| k = ( | ||
| np.fft.fftshift( | ||
| np.fft.fftfreq( | ||
| lightcone.shape[0], d=(boxlen / lightcone.shape[0]).to(un.Mpc).value | ||
| ) | ||
| ) | ||
| * 2 | ||
| * np.pi | ||
| ) | ||
| kperpmesh, kparmesh = np.meshgrid(k, k) | ||
DanielaBreitman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| theta = np.arctan(kparmesh / kperpmesh) | ||
| mu = np.sin(theta) | ||
| for i in range(len(freqs)): | ||
| noisy_lc_ft[:, np.abs(mu) < wedge_mu_min[i], :] = 0.0 | ||
|
|
||
| return np.fft.ifft2(noisy_lc_ft, axes=(1, 2)).real.to(lightcone.unit) | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.