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

Reparametrize pointing #38

Merged
merged 5 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 105 additions & 58 deletions docs/source/tutorials/Synthetic_AtLAST_observations.ipynb

Large diffs are not rendered by default.

125 changes: 90 additions & 35 deletions docs/source/tutorials/Synthetic_MUSTANG2_observations.ipynb

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions docs/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,19 @@ The arrays
- max_el_vel (float): ...
- max_az_acc (float): ...
- max_el_acc (float): ...
- max_baseline (float): meters (only for ALMA)
- baseline (float): meters (only for ALMA)


Pointings
^^^^^^^^^

The next component of the simulation
The next component of the simulation is the pointing, which defines the direction and scan pattern of the observation:::

import maria
daisy_scan = maria.get_pointing("daisy")

mustang = maria.get_array("MUSTANG-2")
We can specify a custom pointing by passing extra arguments to the above, such as::

We can specify a custom array
custom_daisy_scan = maria.get_pointing("daisy", integration_time=600, scan_options={"radius": 2})


Sites
Expand Down Expand Up @@ -114,7 +114,7 @@ Simulation parameters
- max_el_vel (float): ...
- max_az_acc (float): ...
- max_el_acc (float): ...
- max_baseline (float): meters (only for ALMA)
- baseline (float): meters (only for ALMA)

- **pointing:** Scanning strategy
- Predefined configurations: `stare`, `daisy`, `BAF`,
Expand Down
102 changes: 78 additions & 24 deletions maria/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@

here, this_filename = os.path.split(__file__)

all_array_params = utils.io.read_yaml(f"{here}/configs/params.yml")["array"]

ARRAY_CONFIGS = utils.io.read_yaml(f"{here}/configs/arrays.yml")
ARRAY_PARAMS = set()
for key, config in ARRAY_CONFIGS.items():
ARRAY_PARAMS |= set(config.keys())

DISPLAY_COLUMNS = ["description", "field_of_view", "primary_size"]
supported_arrays_table = pd.DataFrame(ARRAY_CONFIGS).T
Expand All @@ -41,13 +40,59 @@ def __init__(self, invalid_array):
)


def get_array_config(array_name, **kwargs):
def generate_array_offsets(geometry, field_of_view, n):
valid_array_types = ["flower", "hex", "square"]

if geometry == "flower":
phi = np.pi * (3.0 - np.sqrt(5.0)) # golden angle in radians
dzs = np.zeros(n).astype(complex)
for i in range(n):
dzs[i] = np.sqrt((i / (n - 1)) * 2) * np.exp(1j * phi * i)
od = np.abs(np.subtract.outer(dzs, dzs))
dzs *= field_of_view / od.max()
return np.c_[np.real(dzs), np.imag(dzs)]
if geometry == "hex":
return generate_hex_offsets(n, field_of_view)
if geometry == "square":
dxy_ = np.linspace(-field_of_view, field_of_view, int(np.ceil(np.sqrt(n)))) / (
2 * np.sqrt(2)
)
DX, DY = np.meshgrid(dxy_, dxy_)
return np.c_[DX.ravel()[:n], DY.ravel()[:n]]

raise ValueError(
"Please specify a valid array type. Valid array types are:\n"
+ "\n".join(valid_array_types)
)


def generate_hex_offsets(n, d):
angles = np.linspace(0, 2 * np.pi, 6 + 1)[1:] + np.pi / 2
zs = np.array([0])
layer = 0
while len(zs) < n:
for angle in angles:
for z in layer * np.exp(1j * angle) + np.arange(layer) * np.exp(
1j * (angle + 2 * np.pi / 3)
):
zs = np.append(zs, z)
layer += 1
zs -= zs.mean()
zs *= 0.5 * d / np.abs(zs).max()

return np.c_[np.real(np.array(zs[:n])), np.imag(np.array(zs[:n]))]


def get_array_config(array_name=None, **kwargs):
if array_name not in ARRAY_CONFIGS.keys():
raise InvalidArrayError(array_name)
ARRAY_CONFIG = ARRAY_CONFIGS[array_name].copy()
array_config = ARRAY_CONFIGS[array_name].copy()
for k, v in kwargs.items():
ARRAY_CONFIG[k] = v
return ARRAY_CONFIG
if k in all_array_params.keys():
array_config[k] = v
else:
raise ValueError(f"'{k}' is not a valid argument for an array!")
return array_config


def get_array(array_name, **kwargs):
Expand All @@ -64,7 +109,7 @@ def generate_dets_from_config(
bands: Mapping,
field_of_view: float,
geometry: str = "hex",
max_baseline: float = 0,
baseline: float = 0,
randomize_offsets: bool = True,
):
dets = pd.DataFrame(
Expand All @@ -89,23 +134,26 @@ def generate_dets_from_config(
band_dets.loc[:, "band_center"] = band_config["band_center"]
band_dets.loc[:, "band_width"] = band_config["band_width"]

dets = pd.concat([dets, band_dets])
dets.index = np.arange(len(dets))
det_offsets_radians = np.radians(
generate_array_offsets(geometry, field_of_view, len(band_dets))
)

offsets_radians = np.radians(
utils.generate_array_offsets(geometry, field_of_view, len(dets))
)
# should we make another function for this?
det_baselines_meters = generate_array_offsets(
geometry, baseline, len(band_dets)
)

# should we make another function for this?
baseline = utils.generate_array_offsets(geometry, max_baseline, len(dets))
# if randomize_offsets:
# np.random.shuffle(offsets_radians) # this is a stupid function.

if randomize_offsets:
np.random.shuffle(offsets_radians) # this is a stupid function.
band_dets.loc[:, "offset_x"] = det_offsets_radians[:, 0]
band_dets.loc[:, "offset_y"] = det_offsets_radians[:, 1]
band_dets.loc[:, "baseline_x"] = det_baselines_meters[:, 0]
band_dets.loc[:, "baseline_y"] = det_baselines_meters[:, 1]
band_dets.loc[:, "baseline_z"] = 0

dets.loc[:, "offset_x"] = offsets_radians[:, 0]
dets.loc[:, "offset_y"] = offsets_radians[:, 1]
dets.loc[:, "baseline_x"] = baseline[:, 0]
dets.loc[:, "baseline_y"] = baseline[:, 1]
dets = pd.concat([dets, band_dets])
dets.index = np.arange(len(dets))

for key in ["offset_x", "offset_y", "baseline_x", "baseline_y"]:
dets.loc[:, key] = dets.loc[:, key].astype(float)
Expand All @@ -123,6 +171,7 @@ class Array:
primary_size: float = 5 # in meters
field_of_view: float = 1 # in deg
geometry: str = "hex"
baseline: float = 0
max_az_vel: float = 0 # in deg/s
max_el_vel: float = np.inf # in deg/s
max_az_acc: float = 0 # in deg/s^2
Expand Down Expand Up @@ -173,14 +222,19 @@ def from_config(cls, config):
if isinstance(config["dets"], Mapping):
field_of_view = config.get("field_of_view", 1)
geometry = config.get("geometry", "hex")
baseline = config.get("baseline", 0) # default to zero baseline
dets = generate_dets_from_config(
config["dets"], field_of_view=field_of_view, geometry=geometry
config["dets"],
field_of_view=field_of_view,
geometry=geometry,
baseline=baseline,
)

return cls(
description=config["description"],
primary_size=config["primary_size"],
field_of_view=field_of_view,
baseline=baseline,
geometry=geometry,
max_az_vel=config["max_az_vel"],
max_el_vel=config["max_el_vel"],
Expand Down Expand Up @@ -219,7 +273,7 @@ def passbands(self, nu):
return nu_mask.astype(float) / nu_mask.sum(axis=-1)[:, None]

def angular_fwhm(self, z):
return utils.gaussian_beam_angular_fwhm(
return utils.beam.gaussian_beam_angular_fwhm(
z=z,
w_0=self.primary_size / np.sqrt(2 * np.log(2)),
f=self.dets.band_center.values,
Expand Down Expand Up @@ -253,7 +307,7 @@ def plot_dets(self):
band_res_arcmins = 60 * np.degrees(
1.22 * 2.998e8 / (1e9 * nom_freq * self.primary_size)
)
# band_res_arcmins = 60 * np.degrees(utils.gaussian_beam_angular_fwhm(z=1e12, w_0=self.primary_size, f=nom_freq))

offsets_arcmins = 60 * np.degrees(self.offsets[band_mask])

ax.add_collection(
Expand Down
2 changes: 1 addition & 1 deletion maria/atmosphere/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def __init__(self, array, pointing, site, verbose=False, **kwargs):

@property
def EL(self):
return utils.xy_to_lonlat(
return utils.coords.xy_to_lonlat(
self.array.offset_x[:, None],
self.array.offset_y[:, None],
self.pointing.az,
Expand Down
Loading
Loading