DISC

This function calculates Direct Normal Irradiance (DNI) from Global Horizontal Irradiance (GHI) and solar zenith angle using the DISC model.

The model estimates DNI through analytical correlations between the global and direct clearness indices. It returns a 2D array where each row contains the modeled DNI, the global clearness index (Kt), and the absolute airmass.

Excel Usage

=DISC(ghi, solar_zenith, times, pressure, min_cos_zenith, max_zenith)
  • ghi (list[list], required): Global horizontal irradiance (W/m^2).
  • solar_zenith (list[list], required): True (not refraction-corrected) solar zenith angles (degrees).
  • times (list[list], required): Timestamps representing day of year in ISO8601 format.
  • pressure (float, optional, default: 101325): Site air pressure (Pa). Default 101325. Use blank for relative airmass.
  • min_cos_zenith (float, optional, default: 0.065): Minimum value of cos(zenith) when calculating clearness index.
  • max_zenith (float, optional, default: 87): Maximum value of zenith to allow in DNI calculation (degrees).

Returns (list[list]): 2D list containing [[dni, kt, airmass]], or an error string.

Example 1: Calculate DNI using DISC model

Inputs:

ghi solar_zenith times pressure
800 40 2024-06-21T12:00:00Z 101325
500 60 2024-06-21T16:00:00Z

Excel formula:

=DISC({800;500}, {40;60}, {"2024-06-21T12:00:00Z";"2024-06-21T16:00:00Z"}, 101325)

Expected output:

Result
907.719 0.788033 1.30368
864.913 0.754585 1.99276
Example 2: DISC using relative airmass with blank pressure

Inputs:

ghi solar_zenith times pressure
650 35 2024-05-15T11:00:00Z
720 50 2024-05-15T13:00:00Z
540 65 2024-05-15T15:00:00Z

Excel formula:

=DISC({650;720;540}, {35;50;65}, {"2024-05-15T11:00:00Z";"2024-05-15T13:00:00Z";"2024-05-15T15:00:00Z"}, "")

Expected output:

Result
349.405 0.592522 1.21942
940.511 0.836412 1.55255
795.77 0.954116 2.35385
Example 3: DISC at high altitude site pressure

Inputs:

ghi solar_zenith times pressure min_cos_zenith
550 55 2024-07-10T09:00:00Z 82000 0.07
780 30 2024-07-10T12:00:00Z
610 48 2024-07-10T14:00:00Z

Excel formula:

=DISC({550;780;610}, {55;30;48}, {"2024-07-10T09:00:00Z";"2024-07-10T12:00:00Z";"2024-07-10T14:00:00Z"}, 82000, 0.07)

Expected output:

Result
770.347 0.723975 1.40718
428.427 0.680012 0.933588
584.044 0.68829 1.20721
Example 4: DISC with a stricter zenith threshold

Inputs:

ghi solar_zenith times max_zenith
250 78 2024-03-15T07:30:00Z 80
420 72 2024-03-15T08:30:00Z
580 66 2024-03-15T09:30:00Z

Excel formula:

=DISC({250;420;580}, {78;72;66}, {"2024-03-15T07:30:00Z";"2024-03-15T08:30:00Z";"2024-03-15T09:30:00Z"}, 80)

Expected output:

Result
688.312 0.868316 4.70361
702.336 0.981485 3.20352
739.511 1 2.44466

Python Code

Show Code
import pandas as pd
import numpy as np
from pvlib.irradiance import disc as result_func

def disc(ghi, solar_zenith, times, pressure=101325, min_cos_zenith=0.065, max_zenith=87):
    """
    Convert GHI to DNI using the Direct Insolation Simulation Code (DISC) model.

    See: https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.irradiance.disc.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        ghi (list[list]): Global horizontal irradiance (W/m^2).
        solar_zenith (list[list]): True (not refraction-corrected) solar zenith angles (degrees).
        times (list[list]): Timestamps representing day of year in ISO8601 format.
        pressure (float, optional): Site air pressure (Pa). Default 101325. Use blank for relative airmass. Default is 101325.
        min_cos_zenith (float, optional): Minimum value of cos(zenith) when calculating clearness index. Default is 0.065.
        max_zenith (float, optional): Maximum value of zenith to allow in DNI calculation (degrees). Default is 87.

    Returns:
        list[list]: 2D list containing [[dni, kt, airmass]], or an error string.
    """
    try:
        def flatten_num(data):
            if not isinstance(data, list): return [float(data)]
            flat = []
            for row in data:
                row = row if isinstance(row, list) else [row]
                for val in row:
                    if val == "": flat.append(float('nan'))
                    else: flat.append(float(val))
            return flat

        def flatten_str(data):
            if not isinstance(data, list): return [str(data)]
            return [str(val) for row in data for val in (row if isinstance(row, list) else [row]) if val != ""]

        ghi_list = flatten_num(ghi)
        zen_list = flatten_num(solar_zenith)
        time_list = flatten_str(times)

        n = len(ghi_list)
        if n == 0 or len(zen_list) != n or len(time_list) != n:
            return "Error: All input arrays must have the same non-zero length"

        idx = pd.DatetimeIndex(time_list)

        if pressure == "":
            p = None
        else:
            p = float(pressure) if pressure is not None else 101325.0
        min_cz = float(min_cos_zenith) if min_cos_zenith is not None else 0.065
        max_z = float(max_zenith) if max_zenith is not None else 87.0

        res = result_func(np.array(ghi_list), np.array(zen_list), idx, pressure=p, min_cos_zenith=min_cz, max_zenith=max_z)

        output = []
        # Res returns an OrderedDict with 'dni', 'kt', 'airmass'
        dnia = res['dni']
        kta = res['kt']
        ama = res['airmass']

        for i in range(n):
            d = float(dnia[i])
            k = float(kta[i])
            a = float(ama[i])
            output.append([d if not pd.isna(d) else "", k if not pd.isna(k) else "", a if not pd.isna(a) else ""])

        return output
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

Global horizontal irradiance (W/m^2).
True (not refraction-corrected) solar zenith angles (degrees).
Timestamps representing day of year in ISO8601 format.
Site air pressure (Pa). Default 101325. Use blank for relative airmass.
Minimum value of cos(zenith) when calculating clearness index.
Maximum value of zenith to allow in DNI calculation (degrees).