:py:mod:`tape.analysis.structure_function`
==========================================

.. py:module:: tape.analysis.structure_function


Subpackages
-----------
.. toctree::
   :titlesonly:
   :maxdepth: 3

   basic/index.rst
   bauer_2009a/index.rst
   bauer_2009b/index.rst
   macleod_2012/index.rst
   schmidt_2010/index.rst


Submodules
----------
.. toctree::
   :titlesonly:
   :maxdepth: 1

   base_argument_container/index.rst
   base_calculator/index.rst
   calculator_registrar/index.rst
   sf_light_curve/index.rst


Package Contents
----------------

Classes
~~~~~~~

.. autoapisummary::

   tape.analysis.structure_function.StructureFunctionArgumentContainer
   tape.analysis.structure_function.StructureFunctionCalculator
   tape.analysis.structure_function.BasicStructureFunctionCalculator
   tape.analysis.structure_function.Bauer2009AStructureFunctionCalculator
   tape.analysis.structure_function.Bauer2009BStructureFunctionCalculator
   tape.analysis.structure_function.Macleod2012StructureFunctionCalculator
   tape.analysis.structure_function.Schmidt2010StructureFunctionCalculator
   tape.analysis.structure_function.StructureFunctionLightCurve



Functions
~~~~~~~~~

.. autoapisummary::

   tape.analysis.structure_function.register_sf_subclasses
   tape.analysis.structure_function.update_sf_subclasses



Attributes
~~~~~~~~~~

.. autoapisummary::

   tape.analysis.structure_function.SF_METHODS


.. py:class:: StructureFunctionArgumentContainer


   This is a container class for less-often-used configuration arguments for
   Structure Function.

   :param band: `list[str]`, optional
                The band information for each lightcurve to be processed. If a value
                is provided for the `band` argument when calling `calc_sf2` directly,
                this value will be ignored. By default None.
   :param lc_id: `int` or `list[int]`, optional
                 The object id for each lightcurve to be processed. If a value is
                 provided for the `lc_id` argument when calling `calc_sf2` directly,
                 this value will be ignored. By default None.
   :param sf_method: {'basic'}, optional
                     This defined which Structure Function calculation method to use when
                     processing lightcurves. By default 'basic'.
   :param band_to_calc: `str` or `list[str]`, optional
                        The bands of the input lightcurves to operate on. If no value is
                        provided, all input bands will be processed. By default None.
   :param combine: `bool`, optional
                   Boolean to determine whether structure function is computed for each
                   light curve independently (combine=False; the default), or computed
                   for all light curves together (combine=True). By default False.
   :param bins: `list[floats]`, optional
                Manually provided time difference bins, if not provided then bins
                are computed using the `bin_method` defined. By default None.
   :param bin_method: {'size', 'length', 'loglength'}, optional
                      The binning method to apply, choices of 'size'; which seeks an even
                      distribution of samples per bin using quantiles, 'length'; which
                      creates bins of equal length in time and 'loglength'; which creates
                      bins of equal length in log time. By default 'size'.
   :param bin_count_target: `int`, optional
                            Target number of samples per time difference bin. By default 100.
   :param ignore_timestamps: `bool`, optional
                             Used to ignore the use of any provided timestamps, instead assuming
                             all measurements are taken at equi-distant times. By default `False`.
   :param random_seed: `int`, optional
                       Used when randomly sampling lightcurves to ensure reproducibility.
                       By default None.
   :param equally_weight_lightcurves: `bool`, optional
                                      Used to ensure that no lightcurves completely dominate the structure
                                      function calculation. For instance if lightcurve LC_1 has N=10
                                      observations and LC_2 has N=100, setting `equally_weight_lightcurves=True`
                                      will calculate all of the time and flux differences (45 for LC_1 and
                                      4950 for LC_2), then randomly sample (without replacement) 45 from
                                      LC_2 when calculating the Structure Function. Note that to bin the
                                      results, we would use the bins calculated based on the 4950
                                      differences or the user provided bins.
                                      By default `False`.
   :param number_lightcurve_samples: `int`, optional
                                     Used to specify the number of time and flux differences to select
                                     from a lightcurve. For Structure Function calculators that inherit
                                     from `StructureFunctionCalculator` and do not implement their own
                                     `_equally_weight_lightcurves` method, the value defined here will
                                     only be used when `equally_weight_lightcurves = True`.
                                     If a value is not provided here, then the default number of
                                     lightcurve samples will be equal to the least number of differences
                                     in the available lightcurves. By default None.
   :param estimate_err: `bool`, optional
                        Specifies if the structure function errors are to be estimated,
                        via bootstraping the sample and taking note of 16 and 84 percentile
                        of the resulting distribution
   :param calculation_repetitions: `int`, optional
                                   Specifies the number of times to repeat the structure function
                                   calculation. Typically this would be used when setting
                                   `estimate_err = True`. By default 1 when not estimating errors,
                                   and 100 when estimating errors.
   :param lower_error_quantile: `float`, optional
                                When calculation_repetitions > 1 we will calculate the
                                `lower_error_quantile` and `upper_error_quantile` quantiles of the
                                results of the structure function calculation and report the
                                difference/2 as 1_sigma_error. Value must be between 0 and 1.
                                By default 0.16.
   :param upper_error_quantile: `float`, optional
                                When calculation_repetitions > 1 we will calculate the
                                `lower_error_quantile` and `upper_error_quantile` quantiles of the
                                results of the structure function calculation and report the
                                difference/2 as 1_sigma_error. Value must be between 0 and 1.
                                By default 0.84.
   :param report_upper_lower_error_separately: `bool`, optional
                                               When true, upper_error_quantile - median and median - lower_error_quantile
                                               will be reported separately. Note, when using `Ensemble.batch`,
                                               additional metadata information will need to be provided.
                                               By default False.

   .. rubric:: Notes

   It may be necessary to extend this dataclass to support new Structure
   Function calculation methods. When doing so, all new properties *must*
   have a default value defined.

   .. py:attribute:: band
      :type: List[str]

      

   .. py:attribute:: lc_id
      :type: Union[int, List[int]]

      

   .. py:attribute:: sf_method
      :type: str
      :value: 'basic'

      

   .. py:attribute:: band_to_calc
      :type: Union[str, List[str]]

      

   .. py:attribute:: combine
      :type: bool
      :value: False

      

   .. py:attribute:: bins
      :type: List[float]

      

   .. py:attribute:: bin_method
      :type: str
      :value: 'size'

      

   .. py:attribute:: bin_count_target
      :type: int
      :value: 100

      

   .. py:attribute:: ignore_timestamps
      :type: bool
      :value: False

      

   .. py:attribute:: random_seed
      :type: int

      

   .. py:attribute:: equally_weight_lightcurves
      :type: bool
      :value: False

      

   .. py:attribute:: number_lightcurve_samples
      :type: int

      

   .. py:attribute:: estimate_err
      :type: bool
      :value: False

      

   .. py:attribute:: lower_error_quantile
      :type: float
      :value: 0.16

      

   .. py:attribute:: upper_error_quantile
      :type: float
      :value: 0.84

      

   .. py:attribute:: report_upper_lower_error_separately
      :type: bool
      :value: False

      

   .. py:method:: __post_init__()



.. py:class:: StructureFunctionCalculator(lightcurves: List[tape.analysis.structure_function.sf_light_curve.StructureFunctionLightCurve], argument_container: tape.analysis.structure_function.base_argument_container.StructureFunctionArgumentContainer)


   Bases: :py:obj:`abc.ABC`

   This is the base class from which all other Structure Function calculator
   methods inherit. Extend this class if you want to create a new Structure
   Function calculation method.

   .. py:method:: calculate()
      :abstractmethod:

      Abstract method that must be implemented by the child class.


   .. py:method:: _bootstrap(random_generator=None)

      This method creates the boostraped samples of difference values


   .. py:method:: _get_difference_values_per_lightcurve()

      Retrieves the number of difference values per lightcurve and stores
      them in an array.


   .. py:method:: _bin_dts(dts)

      Bin an input array of delta times (dts). Supports several binning
      schemes.

      :param dts: 1-d array of delta times to bin
      :type dts: `numpy.ndarray` (N,)

      :returns: **bins** -- The returned bins array.
      :rtype: `numpy.ndarray` (N,)


   .. py:method:: _calculate_binned_statistics(sample_values=None, statistic_to_apply='mean')

      This method will bin delta_t values stored in `self._dts` using the
      bin edges defined by `self._bins`. Then the corresponding `sample_values`
      in each bin will have a statistic measure applied.

      :param sample_values: The values that will be used to calculate the `statistic_to_apply`.
                            If None or not provided, will use `self._all_d_fluxes` by default.
      :type sample_values: `np.ndarray`, optional
      :param statistic_to_apply: The statistic to apply to the values in each delta_t bin, by default
                                 "mean".
      :type statistic_to_apply: str or function, optional

      :returns: A tuple of two lists.
                The first list contains the mean of the delta_t values in each bin.
                The second list contains the result of evaluating the
                statistic measure on the delta_flux values in each delta_t bin.
      :rtype: (`List[float]`, `List[float]`)

      .. rubric:: Notes

      1) Largely speaking this is a wrapper over Scipy's `binned_statistic`,
      so any of the statistics supported by that function are valid inputs here.

      2) It is expected that the shapes of `self._dts` and `sample_values` are
      the same. Additionally, any entry at the i_th index of `self._dts` must
      correspond to the same pair of observations as the entry at the i_th
      index of `sample_values`.


   .. py:method:: name_id() -> str
      :staticmethod:
      :abstractmethod:

      This method will return the unique name of the Structure Function
      calculation method.


   .. py:method:: expected_argument_container() -> type
      :staticmethod:
      :abstractmethod:

      This method will return the argument container class type (not an
      instance) that the Structure Function calculation method requires in
      order to perform it's calculations.



.. py:class:: BasicStructureFunctionCalculator(lightcurves: List[tape.analysis.structure_function.sf_light_curve.StructureFunctionLightCurve], argument_container: tape.analysis.structure_function.base_argument_container.StructureFunctionArgumentContainer)


   Bases: :py:obj:`tape.analysis.structure_function.base_calculator.StructureFunctionCalculator`

   SF calculation method that calculates excess variance directly as a
   variance of observations with observational errors subtracted.
   For reference, please see Equation 12 in https://arxiv.org/abs/1604.05858

   .. py:method:: calculate()

      Abstract method that must be implemented by the child class.


   .. py:method:: name_id() -> str
      :staticmethod:

      This method will return the unique name of the Structure Function
      calculation method.


   .. py:method:: expected_argument_container() -> type
      :staticmethod:

      This method will return the argument container class type (not an
      instance) that the Structure Function calculation method requires in
      order to perform it's calculations.



.. py:class:: Bauer2009AStructureFunctionCalculator(lightcurves: List[tape.analysis.structure_function.sf_light_curve.StructureFunctionLightCurve], argument_container: tape.analysis.structure_function.base_argument_container.StructureFunctionArgumentContainer)


   Bases: :py:obj:`tape.analysis.structure_function.base_calculator.StructureFunctionCalculator`

   This class implements the structure function calculation described in
   Eqn. 4 of Bauer et al. 2009, 2009ApJ...696.1241B [https://arxiv.org/abs/0902.4103]

   `SF(tau) = sqrt( mean(delta_flux^2) - mean(err^2) )`

   Note that the return value is structure function squared.

   Additional references:
   Graham et al. 2014MNRAS.439..703G [https://arxiv.org/abs/1401.1785]

   .. py:method:: calculate()

      Abstract method that must be implemented by the child class.


   .. py:method:: name_id() -> str
      :staticmethod:

      This method will return the unique name of the Structure Function
      calculation method.


   .. py:method:: expected_argument_container() -> type
      :staticmethod:

      This method will return the argument container class type (not an
      instance) that the Structure Function calculation method requires in
      order to perform it's calculations.



.. py:class:: Bauer2009BStructureFunctionCalculator(lightcurves: List[tape.analysis.structure_function.sf_light_curve.StructureFunctionLightCurve], argument_container: tape.analysis.structure_function.base_argument_container.StructureFunctionArgumentContainer)


   Bases: :py:obj:`tape.analysis.structure_function.base_calculator.StructureFunctionCalculator`

   This class implements the structure function calculation described in
   Eqn. 5 of Bauer et al. 2009, 2009ApJ...696.1241B [https://arxiv.org/abs/0902.4103]

   `SF(tau) = sqrt( (pi/2) * mean(abs(delta_flux))^2 - mean(err^2) )`

   Note that the return value is structure function squared.

   Additional references:
   Graham et al. 2014MNRAS.439..703G [https://arxiv.org/abs/1401.1785]

   .. py:method:: calculate()

      Abstract method that must be implemented by the child class.


   .. py:method:: name_id() -> str
      :staticmethod:

      This method will return the unique name of the Structure Function
      calculation method.


   .. py:method:: expected_argument_container() -> type
      :staticmethod:

      This method will return the argument container class type (not an
      instance) that the Structure Function calculation method requires in
      order to perform it's calculations.



.. py:class:: Macleod2012StructureFunctionCalculator(lightcurves: List[tape.analysis.structure_function.sf_light_curve.StructureFunctionLightCurve], argument_container: tape.analysis.structure_function.base_argument_container.StructureFunctionArgumentContainer)


   Bases: :py:obj:`tape.analysis.structure_function.base_calculator.StructureFunctionCalculator`

   This class implements the structure function calculation described in
   MacLeod et al. 2012, 2012ApJ...753..106M [https://arxiv.org/abs/1112.0679]
   MacLeod et al. 2012, Erratum 2014ApJ...782..119M

   `SF_obs(deltaT) = 0.74 * IQR`

   Where `IQR` is the interquartile range between 25% and 75% of the sorted
   (y(t) - y(t+delta_t)) distribution.

   Note that the return value is structure function squared.

   Additional references:
   Kozlowski 2016, 2016ApJ...826..118K [https://arxiv.org/abs/1604.05858]

   .. py:method:: calculate()

      Abstract method that must be implemented by the child class.


   .. py:method:: calculate_iqr_sf2_statistic(input)

      For a given set of binned metrics (in this case delta fluxes) calculate
      the interquartile range.

      :param input: The delta flux values that correspond to a given delta time bin.
      :type input: `np.ndarray` (N,)

      :returns: Result of calculation defined in MacLeod et al. 2012, Erratum 2014ApJ...782..119M:

                `SF(dt) = 0.74 * IQR`
      :rtype: float


   .. py:method:: name_id() -> str
      :staticmethod:

      This method will return the unique name of the Structure Function
      calculation method.


   .. py:method:: expected_argument_container() -> type
      :staticmethod:

      This method will return the argument container class type (not an
      instance) that the Structure Function calculation method requires in
      order to perform it's calculations.



.. py:class:: Schmidt2010StructureFunctionCalculator(lightcurves: List[tape.analysis.structure_function.sf_light_curve.StructureFunctionLightCurve], argument_container: tape.analysis.structure_function.base_argument_container.StructureFunctionArgumentContainer)


   Bases: :py:obj:`tape.analysis.structure_function.base_calculator.StructureFunctionCalculator`

   This class implements the structure function calculation described in
   Eqn. 2 of Schmidt et al. 2010, 2010ApJ...714.1194S [https://arxiv.org/abs/1002.2642]
   Schmidt et al. 2010, Erratum 2010ApJ...721.1941S

   `SF(delta_t) = mean(sqrt(pi/2) * abs(delta_flux_i,j) - sqrt(err_i^2 + err_j^2))`

   Note that the return value is structure function squared.

   Additional references:
   Graham et al. 2014MNRAS.439..703G [https://arxiv.org/abs/1401.1785]

   .. py:method:: calculate()

      Abstract method that must be implemented by the child class.


   .. py:method:: name_id() -> str
      :staticmethod:

      This method will return the unique name of the Structure Function
      calculation method.


   .. py:method:: expected_argument_container() -> type
      :staticmethod:

      This method will return the argument container class type (not an
      instance) that the Structure Function calculation method requires in
      order to perform it's calculations.



.. py:data:: SF_METHODS

   

.. py:function:: register_sf_subclasses()

   This method will identify all of the subclasses of `StructureFunctionCalculator`
   and build a dictionary that maps `name : subclass`.

   :returns: A dictionary of all of subclasses of `StructureFunctionCalculator`. Where
             the str returned from `subclass.name_id()` is the key, and the class is
             the value.
   :rtype: dict

   :raises ValueError: If a duplicate key is found, a ValueError will be raised. This would
       likely occur if a user copy/pasted an existing subclass but failed to
       update the unique name_id string.


.. py:function:: update_sf_subclasses()

   This function is used to register newly created subclasses of the
   `StructureFunctionCalculator`.


.. py:class:: StructureFunctionLightCurve(times: numpy.ndarray, fluxes: numpy.ndarray, errors: numpy.ndarray)


   Bases: :py:obj:`tape.analysis.light_curve.LightCurve`

   This base class is meant to support various analysis routines and be
   extended as needed. (Hence it's location in the `analysis` package.)

   The base class ensures that the data for a single lightcurve is well formed.
   Namely that the input data is all of the same length, with NaN's removed and
   that there are enough observations to perform a given analysis.

   .. py:method:: _calculate_differences()

      Calculate the difference between all possible pairs of time and flux.
      Also calculate the sum of all possible pairs of error^2. To avoid
      duplicate values, we filter out any differences that correspond to a
      time difference less than 0.


   .. py:method:: select_difference_samples(number_of_samples: Optional[int] = None, random_generator: Optional[numpy.random.Generator] = None)

      Take a random sample of time and flux differences and the sum of squared
      errors. The samples are selected without replacement. The resulting
      sub-sample is not guaranteed to have the same order as the input
      differences.

      :param number_of_samples: Defines the number of samples to be randomly selected from the total
                                number of difference values. If not specified, take all of the
                                avaliable values
      :type number_of_samples: int, optional
      :param random_generator: A Numpy random.Generator to sample the lightcurve difference. This
                               allows for repeatable random samples to be selected. By default None.
      :type random_generator: np.random.Generator, optional

      :raises ValueError: If samples are requested than are present in the light curve raise
          ValueError.



