Array Configuration & Subarrays#
Note
Subarray simulation is especially important for the SKA Observatory, as both SKA-LOW and SKA-MID will be constructed and commissioned in stages. The ability to simulate and analyze subarrays is essential for realistic planning, commissioning, and science verification during the phased build-out of these telescopes.
Overview#
Pyralysis supports flexible subarray simulation and dynamic updates to the interferometer configuration. This allows you to:
Simulate phased subarrays for commissioning and science verification
Test different array configurations without recreating the entire setup
Model array failures by removing specific antennas
Analyze performance of different subarray configurations
Array Configuration Files#
Antenna configurations are typically provided as text files with a standard format:
# coordsys = ECEF
# observatory = VLA
-1605504.5 -5042597.4 3552116.5 25.0 VLA01
-1605415.4 -5043423.5 3551014.6 25.0 VLA02
-1605326.3 -5044259.6 3549912.7 25.0 VLA03
...
File Format: - Line 1: Coordinate system (typically ECEF) - Line 2: Observatory name - Subsequent lines: X, Y, Z coordinates (meters), diameter (meters), antenna ID
Loading Array Configurations#
Use the AntennaConfigurationIo class to load array configurations:
from pyralysis.io.antenna_config_io import AntennaConfigurationIo
# Load array configuration
interferometer = AntennaConfigurationIo(input_name="path/to/array.cfg").read()
print(f"Loaded {len(interferometer.antenna_array.antennas)} antennas")
Creating Subarrays#
Pyralysis provides several methods to create subarrays by filtering antennas:
Filtering by Radius#
Create a subarray within a specific radius from the array center:
from pyralysis.simulation.core.antenna_array import AntennaArray
# Filter antennas within 1000 meters from array center
subarray = antenna_array.filter_by_radius(radius=1000.0)
print(f"Subarray contains {len(subarray.antennas)} antennas")
Filtering by Diameter Range#
Select antennas within a specific diameter range:
# Filter antennas with diameters between 10 and 25 meters
subarray = antenna_array.filter_by_diameter_range(
min_diameter=10.0,
max_diameter=25.0
)
Filtering by Antenna IDs#
Include or exclude specific antennas by ID:
# Include specific antennas
subarray = antenna_array.filter_by_ids(
ids=['VLA01', 'VLA02', 'VLA03'],
exclude=False
)
# Exclude specific antennas
subarray = antenna_array.filter_by_ids(
ids=['VLA25', 'VLA26'],
exclude=True
)
Observer Pattern for Dynamic Updates#
The Interferometer class automatically tracks changes to its AntennaArray:
When you modify the antenna array (e.g., by filtering), the interferometer is notified
Baselines and other dependent properties are automatically recalculated
All geometric and simulation calculations remain consistent
Example: Dynamic Subarray Creation
from pyralysis.simulation.core.interferometer import Interferometer
# Create interferometer with full array
interferometer = Interferometer(
antenna_array=antenna_array,
coordinate_system=coordinate_system,
time_system=time_system
)
# Create subarray by filtering
interferometer.antenna_array = interferometer.antenna_array.filter_by_radius(radius=1000.0)
# The interferometer automatically updates its baselines and geometry
print(f"Updated baselines: {len(interferometer.baselines)}")
By default, the primary beam is enabled on the interferometer; set primary_beam_enabled=False when creating the Interferometer for ideal visibilities without beam attenuation.
Advanced Subarray Operations#
Combine multiple filtering operations for complex subarray configurations:
# Create a subarray with specific criteria
subarray = (antenna_array
.filter_by_radius(radius=1500.0)
.filter_by_diameter_range(min_diameter=15.0, max_diameter=30.0)
.filter_by_ids(ids=['VLA01', 'VLA02'], exclude=True))
# Apply to interferometer
interferometer.antenna_array = subarray
Performance Considerations#
Memory Efficiency: Subarray operations are memory-efficient and don’t duplicate data
Baseline Calculation: Automatic recalculation ensures consistency but may take time for large arrays
Chunking: Dask chunking is preserved when creating subarrays
In-place Operations: Use inplace=True for memory-efficient modifications
Best Practices:
# Efficient: Modify in place for large arrays
antenna_array.filter_by_radius(radius=1000.0, inplace=True)
# Alternative: Create new subarray (default behavior)
subarray = antenna_array.filter_by_radius(radius=1000.0)
Use Cases#
SKA Observatory: - Simulate phased commissioning of SKA-LOW and SKA-MID - Test different subarray configurations during construction - Validate science cases with partial arrays
General Applications: - Commissioning new arrays - Testing array configurations - Modeling antenna failures - Performance analysis of different setups
Example: SKA-LOW Subarray Simulation
# Simulate SKA-LOW with only core stations
core_subarray = antenna_array.filter_by_radius(radius=500.0)
# Simulate with core + intermediate stations
intermediate_subarray = antenna_array.filter_by_radius(radius=1000.0)
# Compare performance
core_interferometer = Interferometer(antenna_array=core_subarray, ...)
intermediate_interferometer = Interferometer(antenna_array=intermediate_subarray, ...)