<reponame>helvecioneto/sdt
import pvlib as pvl
import numpy as np

def sol_dqc_01(dframe_,dict_):

    ### COPIA DO REAL
    dqc_ = dframe_.copy()
    dqc_.columns = dqc_.columns.droplevel(1)
 
    ## Le dicionario
    try:
        station = dframe_.acronym.unique()[0]
        id_ = int(dict_.loc[dict_['Sigla'] == station]['Id'].values[0])
        lat_ = dict_.loc[dict_['Sigla'] == station]['Latitude'].values[0]
        lon_ = dict_.loc[dict_['Sigla'] == station]['Longitude'].values[0]
        alt_ = dict_.loc[dict_['Sigla'] == station]['Altitude'].values[0]
    except:
        print('Station or ID not set on Dictionary!!! -> ',station)

    ## FOR LINE IN DATAFRAME
    for i,row in dqc_.iterrows():
        ### Constante solar ajustada para distância Terra-Sol
        sa = pvl.irradiance.get_extra_radiation(datetime_or_doy=row.timestamp, solar_constant=1366.1, method='spencer')

        ### Ângulo do zênite solar
        AZS = pvl.solarposition.spa_python(time=row.timestamp,latitude=lat_,longitude=lon_,altitude=alt_)['zenith'].values[0]

        ## Nas fórmulas, se AZS > 90º u0 é considerado 0
        if AZS > 90:
            u0 = 0
        else:
            u0 = np.cos(np.radians(AZS))

        ### Global Horizontal (Wm²)
        glob_avg_dqc = glo_avg_validation(value=row['glo_avg'],value_std=row['glo_std'],dif=row['dif_avg'],ghi=row['glo_avg'],sa_=sa,u0_=u0,azs_=AZS)

        ### Direta Normal (Wm²)
        dir_avg_dqc = dir_avg_validation(value=row['dir_avg'],value_std=row['dir_std'],dni=row['dir_avg'],ghi=row['glo_avg'],dif=row['dif_avg'],sa_=sa,u0_=u0,azs_=AZS)

        ### Difusa (Wm²)
        dif_avg_dqc = dif_avg_validation(value=row['dif_avg'],value_std=row['dif_std'],dif=row['dif_avg'],ghi=row['glo_avg'],sa_=sa,u0_=u0,azs_=AZS)

        ### Onda Longa (Wm²)
        lw_avg_dqc = lw_avg_validation(value=row['lw_avg'],value_std=row['lw_std'])

        ### PAR (umols s-¹m-²)
        par_avg_dqc = par_avg_validation(value=row['par_avg'],value_std=row['par_std'],sa_=sa,u0_=u0)

        ### Iluminância (klux)
        lux_avg_dqc = par_avg_validation(value=row['lux_avg'],value_std=row['lux_std'],sa_=sa,u0_=u0)


        print(row['timestamp'],row['lux_avg'],lux_avg_dqc)


    return dqc_,dframe_


# Routine validation: Global Radiation (W/m²)
def glo_avg_validation(value,value_std,dif,ghi,sa_,u0_,azs_):

    # ### desvio padrão ≠ 0 (zero)
    # ## Por enquanto critério não aplicável devido a problemas no desvio padrão em arquivos antigos.
    # if value_std == 0:
    #     ## REPROVADO DESVIO PADRAO
    #     return '5552'

    ## FLAG VERIFICATION
    if value == -5555 or value == 3333:
        return '5555'

    # Start of the routine validation: Global Radiation (W/m²)
    else:
        ### mín.: -4
        ### máx.: Sa × 1,5 × µ0^1,2 + 100
        min_v = - 4
        max_v = float(sa_) * 1.5 * (float(u0_) ** (1.2)) + 100

        ## CHECK LEVEL 01
        if value >= min_v and value <= max_v:
            ## APROVADO LEVEL 01
            min_v2 = - 2
            max_v2 = float(sa_) * 1.2 * (float(u0_) ** (1.2)) + 50

            ## CHECK LEVEL 02
            if value >= min_v2 and value <= max_v2:

                ##CHECK LEVEL 03
                ## (Gueymard,2015)
                ## AZS < 75
                if ghi > 50 and azs_ < 75:
                    if (dif / ghi) < 1.05:
                        return '5999'
                    else:
                        return '5299'
                ## AZS > 75
                elif ghi > 50 and azs_ > 75:
                    if (dif / ghi) < 1.10:
                        return '5999'
                    else:
                        return '5299'

                ## LABREN
                elif ghi < 50:
                    if dif - ghi < 15:
                        return '5999'
                    else:
                        return '5299'

                ## REPROVADO LEVEL 03
                else:
                    return '5299'

            ## REPROVADO LEVEL 02
            else:
                return '5529'

        ## REPROVADO LEVEL 01
        else:
            return '5552'


# Routine validation: Direta Normal (W/m²)
def dir_avg_validation(value,value_std,dni,ghi,dif,sa_,u0_,azs_):

    # ### desvio padrão ≠ 0 (zero)
    # ## Por enquanto critério não aplicável devido a problemas no desvio padrão em arquivos antigos.
    # if value_std == 0:
    #     ## REPROVADO DESVIO PADRAO
    #     return '5552'

    ## FLAG VERIFICATION
    if value == -5555 or value == 3333:
        return '5555'

    # Start of the routine validation: Direta Normal (W/m²)
    else:
        ### mín.: -4
        ### máx.: Sa
        min_v = - 4
        max_v = float(sa_)

        ## CHECK LEVEL 01
        if value >= min_v and value <= max_v:
            ## APROVADO LEVEL 01
            min_v2 = - 2
            max_v2 = float(sa_) * 0.95 * (float(u0_) ** (0.2)) + 10

            ## CHECK LEVEL 02
            if value >= min_v2 and value <= max_v2:
                ##CHECK LEVEL 03

                ## CHECK LEVEL 03
                if (dni * u0_) - 50 <= ghi * (ghi - dif):
                    ## CHECAR ESSE DUPLO IF
                    if ghi * (ghi - dif) <= dni:
                        return '5999'
                    ## REPROVADO LEVEL 03
                    else:
                        return '5299' 
                ## REPROVADO LEVEL 03
                else:
                    return '5299' 

            ## REPROVADO LEVEL 02
            else:
                return '5529'
        ## REPROVADO LEVEL 01
        else:
            return '5552'

# Routine validation: Difusa (W/m²)
def dif_avg_validation(value,value_std,dif,ghi,sa_,u0_,azs_):

    # ### desvio padrão ≠ 0 (zero)
    # ## Por enquanto critério não aplicável devido a problemas no desvio padrão em arquivos antigos.
    # if value_std == 0:
    #     ## REPROVADO DESVIO PADRAO
    #     return '5552'

    ## FLAG VERIFICATION
    if value == -5555 or value == 3333:
        return '5555'

    # Start of the routine validation: Difusa (W/m²)
    else:
        min_v = - 4
        max_v = float(sa_) * 0.95 * (float(u0_) ** (1.2)) + 50

        ## CHECK LEVEL 01
        if value >= min_v and value <= max_v:

            ## APROVADO LEVEL 01
            min_v2 = - 2
            max_v2 = float(sa_) * 0.75 * (float(u0_) ** (1.2)) + 30

            ## CHECK LEVEL 02
            if value >= min_v2 and value <= max_v2:

                ##CHECK LEVEL 03
                ## AZS < 75
                if ghi > 50 and azs_ < 75:
                    if (dif / ghi) < 1.05:
                        return '5999'
                    else:
                        return '5299'
                ## AZS > 93
                elif ghi > 50 and azs_ > 93:
                    if (dif / ghi) < 1.10:
                        return '5999'
                    else:
                        return '5299'

                ## LABREN
                elif ghi > 50:
                        return '5999'

                ## REPROVADO LEVEL 03
                else:
                    return '5299'

            ## REPROVADO LEVEL 02
            else:
                return '5529'

        ## REPROVADO LEVEL 01
        else:
            return '5552'

def lw_avg_validation(value,value_std):
    # ### desvio padrão ≠ 0 (zero)
    # ## Por enquanto critério não aplicável devido a problemas no desvio padrão em arquivos antigos.
    # if value_std == 0:
    #     ## REPROVADO DESVIO PADRAO
    #     return '5552'

    ## FLAG VERIFICATION
    if value == -5555 or value == 3333:
        return '0555'

    # Start of the routine validation: Onda Longa (W/m²)
    else:
        min_v = 40
        max_v = 700

        ## CHECK LEVEL 01
        if value >= min_v and value <= max_v:

            ## APROVADO LEVEL 01
            min_v2 = 60
            max_v2 = 500

            ## CHECK LEVEL 02
            if value >= min_v2 and value <= max_v2:
                return '0599'

            ## REPROVADO LEVEL 02
            else:
                return '0529'

        ## REPROVADO LEVEL 01
        else:
            return '0552'


def par_avg_validation(value,value_std,sa_,u0_):
    # ### desvio padrão ≠ 0 (zero)
    # ## Por enquanto critério não aplicável devido a problemas no desvio padrão em arquivos antigos.
    # if value_std == 0:
    #     ## REPROVADO DESVIO PADRAO
    #     return '5552'

    ## FLAG VERIFICATION
    if value == -5555 or value == 3333:
        return '0555'

    # Start of the routine validation: PAR
    else:
        min_v = - 4
        max_v = 2.07 * (sa_ * 1.5 * (u0_**1.2) + 100)

        ## CHECK LEVEL 01
        if value >= min_v and value <= max_v:
            ## APROVADO LEVEL 01
            min_v2 = - 2
            max_v2 = 2.07 * (sa_ * 1.2 * (u0_**1.2) + 50)

            ## CHECK LEVEL 02
            if value >= min_v2 and value <= max_v2:
                return '0599'

            ## REPROVADO LEVEL 02
            else:
                return '0529'

        ## REPROVADO LEVEL 01
        else:
            return '0552'


def lux_avg_validation(value,value_std,sa_,u0_):
    # ### desvio padrão ≠ 0 (zero)
    # ## Por enquanto critério não aplicável devido a problemas no desvio padrão em arquivos antigos.
    # if value_std == 0:
    #     ## REPROVADO DESVIO PADRAO
    #     return '5552'

    ## FLAG VERIFICATION
    if value == -5555 or value == 3333:
        return '0555'

    # Start of the routine validation: PAR
    else:
        min_v = - 4
        max_v = 0.1125 * (sa_ * 1.5 * (u0_**1.2) + 100)

        ## CHECK LEVEL 01
        if value >= min_v and value <= max_v:
            ## APROVADO LEVEL 01
            min_v2 = - 2
            max_v2 = 0.1125 * (sa_ * 0.95 * (u0_**1.2) + 50)

            ## CHECK LEVEL 02
            if value >= min_v2 and value <= max_v2:
                return '0599'

            ## REPROVADO LEVEL 02
            else:
                return '0529'

        ## REPROVADO LEVEL 01
        else:
            return '0552'