def rotateZernike(z, i0, angledeg):
    """

    Inputs:
    <z>        : 1D array of floating point values (zernike coefficients)
    <i0>       : scalar, integer. It is the zernike index of the 1st coeff contained in <z>.
    <angledeg> : scalar, floating point

    Output:
    An array of floating-point values (zernike coefficients of the rotated wavefront).

    For a couple [a,b] of Zernike coefficients with same azimutal order
    m, returns the couple of coefficients of Zernike decomposition
    rotated by an angle <angledeg> (angle expressed in degrees)

    """
    # number of coefficients contained in the vector z
    nzer = z.shape[0]

    # index of the last Zernike coefficient
    imax = nzer+i0-1
    # check whether <imax> is ok or not
    errorImax = checkConsistencyOfNumberOfElementsOfZernikeArray( nzer+i0-1 )
    # produces an error if not consistent
    if( errorImax ):
        print "The number of Zernike modes (%d to %d) does not entierely fill a radial order." % (i0, imax)
        print "A coefficient is missing : it is impossible to rotate the wavefront properly."
        print "I will ignore the last Zernike coefficient."
        nzer = nzer-1


    # allocates memory for the result: an array of <nzer> coefficient, same length as <z>, floats.
    z_output = np.zeros(nzer)

    k = 0
    while(k<nzer):
        i  = k+i0      # index of the Zernike mode, as described in the literature (Z_1 is piston)
        # determine radial and azimutal orders, called <n> and <m>
        n,m = gral_zer.nm(i)
        if( m==0 ):
            # do nothing, coefficient is unchanged
            z_output[k] = z[k]
        else:
            if( (i&1)==0 ):    # equivalent to "i modulo 2"
                # if i is an even number (2,4,6,..)
                tmp = rotateCoupleOfCoeffs(z[k], z[k+1], m, angledeg)
                z_output[k]   = tmp[0]
                z_output[k+1] = tmp[1]
            else:
                # if i is an odd number (1,3,5,7,...)
                tmp = rotateCoupleOfCoeffs(z[k+1], z[k], m, angledeg)
                # warning: SWAP coefficients !!!!
                z_output[k]   = tmp[1]
                z_output[k+1] = tmp[0]
            # skip the next coefficient z[k+1], that has already been processed
            k = k+1
        k = k+1

    return z_output
def flipZernike(z, i0):
    """

    Input parameters:
    <z> : 1D array of zernike coefficients
    <i0> : Zernike index of the first element of the array

    Output parameters:
    1D array of zernike coefficients

    The function returns a list of zernike coefficient that represent a
    flipped version of the wavefront wrt to the input. The flip is
    operated around the X axis (equation: y=0, i.e. "horizontal" axis).

    Note: the Yorick version provides a new array of values in
    output. For a C version of the code, it would be MUCH better to do
    the transformation in place, just modifying the coefficients in the
    same memory area, as the transformation is straightforward (just
    modifying the sign of some of the coefficients).
    """
    # number of coefficients contained in the vector z
    nzer = z.shape[0]

    # allocates memory for the result: an array of <nzer> coefficient, same length as <z>, floats.
    z_output = np.zeros(nzer)

    for k in range(nzer):
        i= k+i0   # index of the Zernike mode, as described in the literature (Z_1 is piston)
        # determine radial and azimutal orders, called <n> and <m> (well, actually, n is not required here...)
        n,m = gral_zer.nm(i)
        if( m==0 ):
            z_output[k] = z[k]   # coeff unchanged
        else:
            if( (i&1)==1 ) :
                # if i is an odd number (1,3,5..)
                z_output[k] = -z[k]   # change sign
            else :
                # if i is an even number (2,4,6..)
                z_output[k] = z[k]   # coeff unchanged

    return z_output
def checkConsistencyOfNumberOfElementsOfZernikeArray( imax ):
    """
    Input:
    <imax> : scalar, integer. A number of Zernike mode.

    Output:
    An boolean: True=error, False=no error

    The function returns a boolean error code.
    True when there is an error, False when there is no error.

     """
    # determine radial and azimutal orders n and m
    n,m = gral_zer.nm(imax)
    if( m==0 ):
        return False
    n2 = n//2    # Warning : interger division !  5//2 = 2, and not 2.500 !!
    if( (imax&1)==(n2&1) ):
    # If parity of <imax> and <n2> is the same: not good.
        return True
    else:
        # If parity is different: ok this is correct.
        return False