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:

.. code-block:: text

   # 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:

.. code-block:: python

   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:

.. code-block:: python

   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:

.. code-block:: python

   # 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:

.. code-block:: python

   # 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**

.. code-block:: python

   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:

.. code-block:: python

   # 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:**

.. code-block:: python

   # 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**

.. code-block:: python

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

----

:doc:`simulation` | :doc:`optimization`
