TO DO: Add logit bounds
    determine AUC and 95% confidence intervals (CI)
    :param roc_structure: auc_structure: list [(id, best_score, best_query, status, fpf, tpf), ..., ]
    :param sort_order: either 'asc' (binding free energy estimates) or 'dsc' (probabilities)
    :return (AUC, AUC - CI, AUC + CI): tuple

def calculate_auc(auc_structure, sort_order, diff = None):
    """
    TO DO: Add logit bounds
    determine AUC and 95% confidence intervals (CI)
    :param roc_structure: auc_structure: list [(id, best_score, best_query, status, fpf, tpf), ..., ]
    :param sort_order: either 'asc' (binding free energy estimates) or 'dsc' (probabilities)
    :return (AUC, AUC - CI, AUC + CI): tuple
    """

    # sort by best scores
    if sort_order == 'asc':
        auc_structure.sort(key=lambda x: float(x[1]))
    elif sort_order == 'dsc':
        auc_structure.sort(key=lambda x: float(x[1]), reverse=True)

    # AUC calculation <tpf>d
    auc = 0.                         # auc average
    n = 0                           # decoy count
    for mol in auc_structure:
        status = mol[3]
        if status == '0':
            tpf = mol[5]
            n += 1
            auc += tpf
    if n == 0:
        auc = 0
    else:
        auc = (1. / n) * auc

    if diff:
        return auc
    else:
        # confidence interval calculations
        n = len([x for x in auc_structure if x[3] == '0'])          # no of decoys
        p = len([x for x in auc_structure if x[3] == '1'])          # no of actives
        aucvar_a, aucvar_d = calculate_auc_var(auc_structure)       # variance due to active and decoys
        se = (aucvar_a / p + aucvar_d / n) ** 0.5                   # standard error
        ci = se * stats.t.ppf(1 - 0.025, n + p - 1)                 # 95% confidence interval

        # bounds
        lower = auc - ci
        upper = auc + ci

        # dumb limit checking (ADD LOGIT FUNCTION)
        if lower < 0:
         lower = 0.0
        if upper > 1:
          upper = 1.0

        return (auc, lower, upper)