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).