Module mjoindices.omi.postprocessing_rotation_approach

Contains the post-processing of the EOFs as described in Weidman et al. (2022). This is an alternative post-processing approach and does not lead to the same results as shown in Kiladis et al. (2014). It reduces noise and avoids potential degeneracy issues.

The post-processing procedure follows the below steps:

  1. Corrects spontaneous sign changes in the EOFs (same as the original procedure)

  2. Projects EOFs at DOY = n-1 onto EOF space for DOY = n. This is done to reduce spurious oscillations between EOFs on sequential days

  3. Rotate the projected EOFs by 1/366 (or 1/365) per day to ensure continuity across January to December

  4. Renormalize the EOFs to have a length of 1 (this is a small adjustment to account for small numerical errors).

mjoindices.omi.postprocessing_rotation_approach.angle_between_eofs(reference: ~mjoindices.empirical_orthogonal_functions.EOFData, target=<class 'mjoindices.empirical_orthogonal_functions.EOFData'>)[source]

Calculates angle between two EOF vectors to determine their “closeness” \(theta = arccos(t . r / (||r||*||t||))\).

Parameters:
  • reference – The reference-EOFs. This is usually the EOF pair of the previous or “first” DOY.

  • target – The EOF data from the target DOY.

Returns:

A tuple of the angles between the reference and target EOFs for both EOF1 and EOF2

mjoindices.omi.postprocessing_rotation_approach.angle_btwn_vectors(vector1, vector2)[source]

Calculates the angle between vectors, \(theta = arccos(t . r / (||r||*||t||))\).

Parameters:
  • vector1 – 1d vector, generally corresponding to EOF1 or 2 from some DOY

  • vector2 – 1d vector, generally corresponding to EOF1 or 2 from a different DOY

Returns:

scalar angle between vectors 1 and 2, in radians.

mjoindices.omi.postprocessing_rotation_approach.calculate_angle_from_discontinuity(orig_eofs: EOFDataForAllDOYs)[source]

Project the matrix to align with the EOFs from the previous DOY and calculate the resulting discontinuity between January 1 and January 1 after one year of projections. Divide by the number of days in one year to determine the discontinuity used for rotation.

Parameters:

orig_eofs – calculated EOFs, after signs have been changed via spontaneous_sign_changes

Returns:

float of angular discontinuity between EOF1 on DOY1 and EOF1 on DOY1 after a full year of projection, divided by the length of the year.

mjoindices.omi.postprocessing_rotation_approach.normalize_eofs(orig_eofs: EOFDataForAllDOYs) EOFDataForAllDOYs[source]

Normalize all EOFs to have a magnitude of 1.

Parameters:

eofdata – The rotated EOF series.

Returns:

normalized EOFdata for all days.

mjoindices.omi.postprocessing_rotation_approach.post_process_eofs_rotation(eofdata: EOFDataForAllDOYs, sign_doy1reference: bool = True) EOFDataForAllDOYs[source]

Executes the complete post-processing of a series of EOF pairs for all DOYs according to the alterntive procedure described by Weidman et al. (2022).

Postprocessing includes an alignment of EOF signs and a rotation algorithm that rotates the EOFs in three steps:

  1. Projects EOFs at DOY = n-1 onto EOF space for DOY = n. This is done to reduce spurious oscillations between EOFs on sequential days

  2. Rotate the projected EOFs by 1/366 (or 1/365) of the December –> January discontinuity each day to ensure continuity across December to January

  3. Renormalize the EOFs to have a length of 1 (this is a small adjustment to account for small numerical errors).

See documentation of the methods correct_spontaneous_sign_changes_in_eof_series() for EOF sign flipping

Note that it is recommended to use the function calc_eofs_from_olr() to cover the complete algorithm.

Parameters:
Returns:

The postprocessed series of EOFs

mjoindices.omi.postprocessing_rotation_approach.rotate_each_eof_by_delta(orig_eofs: EOFDataForAllDOYs, delta: float) EOFDataForAllDOYs[source]

Use delta calculated by optimization function to rotate original EOFs by delta. First projects EOFs from DOY n-1 onto EOF space for DOY n, then rotates projected EOFs by small angle delta.

Parameters:
  • orig_eofs – calculated EOFs, signs have been changed via spontaneous_sign_changes

  • delta – scalar by which to rotate EOFs. Calculated as the angular discontinuity between EOF1 on DOY1 and EOF1 on DOY1 after a full year of projection, divided by the length of the year.

Returns:

new EOFdata with projected and rotated EOFs.

mjoindices.omi.postprocessing_rotation_approach.rotate_eofs(orig_eofs: EOFDataForAllDOYs) EOFDataForAllDOYs[source]

Rotate EOFs at each DOY to

  1. align with the EOFs of the previous day and

  2. be continuous across December to January boundary.

Described more in detail in :py:func:’post_process_eofs_rotation’

Parameters:

orig_eofs – Calculated EOFs, which already has algined signs between neighboring DOYs.

Returns:

set of rotated EOFs.

mjoindices.omi.postprocessing_rotation_approach.rotation_matrix(delta)[source]

Creates a 2d rotation matrix for corresponding delta.

Parameters:

delta – Scalar angle, in radians, of desired rotation.

Returns:

2x2 rotation matrix that can be used to rotate an Nx2 matrix in the x-y plane counterclockwise by delta.