.. _APIOverview:

API Overview
============

The main functionality of ``aomodel`` is through the :ref:`ReVAR` and :ref:`LongRangeAR` classes. See :ref:`Theory` for
a more thorough description of the **ReVAR** and **Long-Range AR** algorithms.

* Use ``ReVAR`` if you want to capture the spatial and temporal correlations of an input time series of images.
* Use ``LongRangeAR`` if you want to capture the statistics of an input time series of vectors and specify a prediction
  window structure (see :ref:`AdvancedFeatures` for more details).

This guide covers the standard workflow for using both the ``ReVAR`` and ``LongRangeAR`` classes to model and generate
synthetic time series data. Since ``ReVAR`` inherits ``LongRangeAR``, the functionality between the two classes is
very similar.

When using ``ReVAR`` or ``LongRangeAR``, the two most important parameters to specify are:

* ``time_lags``: The backwards time-index shifts to use for the AR component of linear prediction.
* ``num_low_pass_filters``: The number of low-pass filters to use for linear prediction.

These parameters will determine i) the resolution of temporal correlations that the model captures and ii) the
computational expense of running the model to generate synthetic data.

The Core Workflow
-----------------

Using the package generally involves three steps: **Initialization**, **Fitting**, and **Generation**.

1. Initialization
~~~~~~~~~~~~~~~~~

Create an instance of the class.

For ``ReVAR``, you must specify the data mask in addition to the time-lags and number of low-pass filters.

.. code-block:: python

    from aomodel import ReVAR
    import numpy as np

    data_mask = np.ones((5, 5), dtype=bool)

    model = ReVAR(
        data_mask=data_mask,
        time_lags=2,  # Use backward time-index shifts (1, 2)
        num_low_pass_filters=1  # Optional: Add long-term memory
    )

For ``LongRangeAR``, you must specify the vector dimensionality. If using ``ReVAR``, this attribute is inferred from
the data mask.

.. code-block:: python

    from aomodel import LongRangeAR

    model = LongRangeAR(
        vector_dimensionality=25,
        time_lags=2,                # Use backward time-index shifts (1, 2).
        num_low_pass_filters=1      # Optional: Incorporate long-range temporal correlations.
    )

2. Fitting
~~~~~~~~~~

Fit the model to your training data using the ``fit()`` method.

* **Training Data:** For ``ReVAR``, this input must be a 3-D numpy array. For ``LongRangeAR``, it must be a 2-D numpy
  array.
* **LPF Parameters:** If you use low-pass filters, the model will automatically estimate the parameters of the LPFs
  through a cutoff frequency determined from the data's Temporal Power Spectrum (TPS) if you do not provide one. It is
  generally recommended to allow the model to estimate these parameters.

.. code-block:: python

    model.fit(training_data)

**Input Data Requirements**

In addition to satisfying the theoretical assumptions outlined in :ref:`Theory`, the training data must be placed in a
specific shape for each model:

Using ``ReVAR``:

* **Time:** The first axis of the training data corresponds to time-steps.
* **Dimensionality:** The second and third axes of the training data correspond to images.

Using ``LongRangeAR``:

* **Dimensionality:** The rows of your data matrix correspond to vector components.
* **Time:** The columns correspond to time-steps.

3. Generation
~~~~~~~~~~~~~

Generate new synthetic data using ``run()``. The output will preserve the spatial and temporal statistics of the
training data set.

.. code-block:: python

    # Generate 500 new time steps:
    synthetic_data = model.run(num_time_steps=500)

Saving and Loading Models
-------------------------

Training can be computationally expensive. You can save a fitted model to disk and load it later to generate data
without re-fitting.

.. code-block:: python

    # Save the estimated parameters:
    model.save(save_file="my_trained_model.npz")

    # Load into a new instance:
    new_model = ReVAR(load_file="my_trained_model.npz")
    synthetic_data = new_model.run(100)   # Generate synthetic data using the loaded model.

Alternatively, if using ``LongRangeAR``, the usage is identical:

.. code-block:: python

    new_model = LongRangeAR(load_file="my_trained_model.npz")
    data = new_model.run(100)


Evaluating Statistics of Data
-----------------------------

You can use the :ref:`Metrics` module to evaluate the spatial and temporal statistics of either input data or synthetic
data generated by the ``aomodel`` package. The :ref:`Metrics` module uses the **Temporal Power Spectrum (TPS)** to
evaluate temporal statistics and **2-D Structure Function** to evaluate spatial statistics.

Comparing the TPS and structure function of input data with those of synthetic data allows you to determine how well
either ``ReVAR`` or ``LongRangeAR`` matches the statistics of input data. This is demonstrated in the demo files; see
:ref:`Demo` for instructions on running these files.

In the case that the statistical fit of the model is not satisfactory, you can modify the prediction window structure
and the ``time_lags`` and ``num_low_pass_filters`` parameters to improve the model's fit of the spatial and temporal
statistics (respectively).