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, ...)

Simulation Framework | Optimization in Pyralysis