CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pvlib

A comprehensive toolbox for modeling and simulating photovoltaic energy systems.

Pending
Overview
Eval results
Files

clearsky.mddocs/

Clear Sky Models

Calculate clear sky irradiance using multiple models including Ineichen, Bird, Haurwitz, and simplified SOLIS. Clear sky models provide baseline irradiance estimates for system modeling, clear sky detection, and performance analysis.

Capabilities

Ineichen Clear Sky Model

The most commonly used clear sky model, recommended by the IEA Task 12 and WMO.

def ineichen(apparent_zenith, airmass_absolute, linke_turbidity, 
            altitude=0, dni_extra=1366.1):
    """
    Calculate clear sky irradiance using Ineichen model.
    
    Parameters:
    - apparent_zenith: numeric, apparent solar zenith angle in degrees
    - airmass_absolute: numeric, absolute airmass
    - linke_turbidity: numeric, Linke turbidity factor
    - altitude: numeric, altitude above sea level in meters
    - dni_extra: numeric, extraterrestrial direct normal irradiance (W/m^2)
    
    Returns:
    OrderedDict with keys:
    - ghi: global horizontal irradiance (W/m^2)
    - dni: direct normal irradiance (W/m^2)
    - dhi: diffuse horizontal irradiance (W/m^2)
    """

Bird Clear Sky Model

Physically-based clear sky model with detailed atmospheric parameter inputs.

def bird(zenith, airmass_relative, aod380, aod500, precipitable_water, 
        ozone=0.3, pressure=101325.0, dni_extra=1366.1, 
        asymmetry=0.85, albedo=0.2):
    """
    Calculate clear sky irradiance using Bird model.
    
    Parameters:
    - zenith: numeric, solar zenith angle in degrees
    - airmass_relative: numeric, relative airmass
    - aod380: numeric, aerosol optical depth at 380 nm
    - aod500: numeric, aerosol optical depth at 500 nm
    - precipitable_water: numeric, precipitable water in cm
    - ozone: numeric, ozone in atm-cm
    - pressure: numeric, atmospheric pressure in pascals
    - dni_extra: numeric, extraterrestrial direct normal irradiance (W/m^2)
    - asymmetry: numeric, aerosol asymmetry parameter
    - albedo: numeric, ground albedo
    
    Returns:
    OrderedDict with keys:
    - ghi: global horizontal irradiance (W/m^2)
    - dni: direct normal irradiance (W/m^2)
    - dhi: diffuse horizontal irradiance (W/m^2)
    """

Haurwitz Clear Sky Model

Simple empirical clear sky model requiring only solar zenith angle.

def haurwitz(apparent_zenith):
    """
    Calculate clear sky GHI using Haurwitz model.
    
    Parameters:
    - apparent_zenith: numeric, apparent solar zenith angle in degrees
    
    Returns:
    numeric, global horizontal irradiance (W/m^2)
    """

Simplified SOLIS Clear Sky Model

Simplified version of the SOLIS clear sky model.

def simplified_solis(apparent_elevation, aod700=0.1, precipitable_water=1.0, 
                    pressure=101325.0, dni_extra=1366.1):
    """
    Calculate clear sky irradiance using simplified SOLIS model.
    
    Parameters:
    - apparent_elevation: numeric, apparent solar elevation angle in degrees
    - aod700: numeric, aerosol optical depth at 700 nm
    - precipitable_water: numeric, precipitable water in cm
    - pressure: numeric, atmospheric pressure in pascals
    - dni_extra: numeric, extraterrestrial direct normal irradiance (W/m^2)
    
    Returns:
    OrderedDict with keys:
    - ghi: global horizontal irradiance (W/m^2)
    - dni: direct normal irradiance (W/m^2)
    - dhi: diffuse horizontal irradiance (W/m^2)
    """

Linke Turbidity Lookup

Look up Linke turbidity values from monthly climatology database.

def lookup_linke_turbidity(time, latitude, longitude, filepath=None, 
                          interp_turbidity=True):
    """
    Look up Linke turbidity values from climatology database.
    
    Parameters:
    - time: pandas.DatetimeIndex, times for lookup
    - latitude: float, decimal degrees north
    - longitude: float, decimal degrees east
    - filepath: str, path to Linke turbidity file
    - interp_turbidity: bool, interpolate turbidity values
    
    Returns:
    pandas.Series, Linke turbidity values
    """

Clear Sky Detection

Detect clear sky conditions from measured irradiance data.

def detect_clearsky(measured, clearsky, times=None, infer_limits=False, 
                   window_length=10, mean_diff=75, max_diff=75, 
                   lower_line_length=-5, upper_line_length=10, 
                   var_diff=0.005, slope_dev=8, max_iterations=20, 
                   return_components=False):
    """
    Detect clear sky conditions from measured vs. clear sky irradiance.
    
    Parameters:
    - measured: pandas.Series or DataFrame, measured irradiance
    - clearsky: pandas.Series or DataFrame, clear sky irradiance
    - times: pandas.DatetimeIndex, timestamps
    - infer_limits: bool, infer detection limits from data
    - window_length: int, window length for moving statistics
    - mean_diff: numeric, mean difference threshold
    - max_diff: numeric, maximum difference threshold
    - lower_line_length: numeric, lower line length parameter
    - upper_line_length: numeric, upper line length parameter
    - var_diff: numeric, variance difference threshold
    - slope_dev: numeric, slope deviation threshold
    - max_iterations: int, maximum number of iterations
    - return_components: bool, return intermediate results
    
    Returns:
    pandas.Series or tuple, clear sky mask and optional components
    """

Usage Examples

Basic Ineichen Clear Sky Calculation

import pvlib
from pvlib import clearsky, solarposition, atmosphere
import pandas as pd

# Location and time
lat, lon = 40.0583, -74.4057  # Princeton, NJ
times = pd.date_range('2023-06-21', periods=24, freq='H', tz='US/Eastern')

# Solar position
solar_pos = solarposition.get_solarposition(times, lat, lon)

# Atmospheric parameters
airmass = atmosphere.get_relative_airmass(solar_pos['zenith'])
airmass_abs = atmosphere.get_absolute_airmass(airmass)

# Look up Linke turbidity (or use typical value)
linke_turbidity = 3.0  # Typical value for mid-latitudes

# Calculate clear sky irradiance
clear_sky = clearsky.ineichen(
    apparent_zenith=solar_pos['apparent_zenith'],
    airmass_absolute=airmass_abs,
    linke_turbidity=linke_turbidity
)

print("Time, GHI, DNI, DHI")
for i in range(8, 16):  # Show daytime hours
    time_str = times[i].strftime('%H:%M')
    ghi = clear_sky['ghi'].iloc[i]
    dni = clear_sky['dni'].iloc[i]
    dhi = clear_sky['dhi'].iloc[i]
    print(f"{time_str}, {ghi:.0f}, {dni:.0f}, {dhi:.0f}")

Bird Clear Sky Model with Detailed Atmospheric Parameters

import pvlib
from pvlib import clearsky, solarposition, atmosphere
import pandas as pd

# Location and conditions
lat, lon = 35.05, -106.54  # Albuquerque, NM (high altitude, dry)
times = pd.date_range('2023-06-21 12:00', periods=1, tz='US/Mountain')

# Solar position
solar_pos = solarposition.get_solarposition(times, lat, lon, altitude=1619)
zenith = solar_pos['zenith'].iloc[0]

# Atmospheric parameters for high altitude, dry location
airmass_rel = atmosphere.get_relative_airmass(zenith)
aod380 = 0.1  # Low aerosol loading
aod500 = 0.05
precipitable_water = 0.8  # Low water vapor
ozone = 0.25  # Typical ozone
pressure = atmosphere.alt2pres(1619)  # Pressure at altitude

# Calculate clear sky irradiance
clear_sky = clearsky.bird(
    zenith=zenith,
    airmass_relative=airmass_rel,
    aod380=aod380,
    aod500=aod500,
    precipitable_water=precipitable_water,
    ozone=ozone,
    pressure=pressure
)

print(f"Bird clear sky model results:")
print(f"GHI: {clear_sky['ghi']:.0f} W/m²")
print(f"DNI: {clear_sky['dni']:.0f} W/m²")
print(f"DHI: {clear_sky['dhi']:.0f} W/m²")

Comparing Clear Sky Models

import pvlib
from pvlib import clearsky, solarposition, atmosphere
import pandas as pd
import matplotlib.pyplot as plt

# Location and time
lat, lon = 40.0583, -74.4057
times = pd.date_range('2023-06-21 06:00', '2023-06-21 18:00', 
                     freq='H', tz='US/Eastern')

# Solar position and atmospheric parameters
solar_pos = solarposition.get_solarposition(times, lat, lon)
airmass_rel = atmosphere.get_relative_airmass(solar_pos['zenith'])
airmass_abs = atmosphere.get_absolute_airmass(airmass_rel)

# Model comparisons
results = {}

# Ineichen model
results['Ineichen'] = clearsky.ineichen(
    solar_pos['apparent_zenith'], airmass_abs, linke_turbidity=3.0
)

# Haurwitz model (GHI only)
results['Haurwitz'] = {'ghi': clearsky.haurwitz(solar_pos['apparent_zenith'])}

# Simplified SOLIS model
results['SOLIS'] = clearsky.simplified_solis(
    solar_pos['apparent_elevation'],
    aod700=0.1,
    precipitable_water=1.5
)

# Print comparison at solar noon
noon_idx = 12
print("Clear sky model comparison at solar noon:")
print(f"{'Model':<10} {'GHI':<6} {'DNI':<6} {'DHI':<6}")
for model_name, data in results.items():
    ghi = data['ghi'].iloc[noon_idx] if hasattr(data['ghi'], 'iloc') else data['ghi'][noon_idx]
    dni = data.get('dni', [0]*len(times))
    dhi = data.get('dhi', [0]*len(times))
    if hasattr(dni, 'iloc'):
        dni_val = dni.iloc[noon_idx]
        dhi_val = dhi.iloc[noon_idx]
    else:
        dni_val = dni[noon_idx]
        dhi_val = dhi[noon_idx]
    print(f"{model_name:<10} {ghi:<6.0f} {dni_val:<6.0f} {dhi_val:<6.0f}")

Clear Sky Detection

import pvlib
from pvlib import clearsky, solarposition, atmosphere
import pandas as pd
import numpy as np

# Generate synthetic clear sky and measured data
lat, lon = 40.0583, -74.4057
times = pd.date_range('2023-06-21', periods=24, freq='H', tz='US/Eastern')

# Solar position and clear sky
solar_pos = solarposition.get_solarposition(times, lat, lon)
airmass_abs = atmosphere.get_absolute_airmass(
    atmosphere.get_relative_airmass(solar_pos['zenith'])
)
clear_sky = clearsky.ineichen(
    solar_pos['apparent_zenith'], airmass_abs, linke_turbidity=3.0
)

# Create synthetic measured data with some cloudy periods
np.random.seed(42)
measured_ghi = clear_sky['ghi'].copy()
# Add some clouds (reduce irradiance) for certain hours
cloudy_hours = [9, 10, 14, 15]
for hour in cloudy_hours:
    measured_ghi.iloc[hour] *= 0.3 + 0.4 * np.random.random()

# Detect clear sky periods
clear_mask = clearsky.detect_clearsky(
    measured=measured_ghi,
    clearsky=clear_sky['ghi'],
    times=times
)

print("Clear sky detection results:")
print("Hour, Measured GHI, Clear Sky GHI, Clear Sky?")
for i in range(8, 17):  # Daytime hours
    hour = times[i].hour
    measured = measured_ghi.iloc[i]
    clear = clear_sky['ghi'].iloc[i]
    is_clear = clear_mask.iloc[i]
    print(f"{hour:2d}:00, {measured:6.0f}, {clear:6.0f}, {is_clear}")

Location-Specific Linke Turbidity

import pvlib
from pvlib import clearsky
import pandas as pd

# Multiple locations with different turbidity characteristics
locations = [
    {'name': 'Rural', 'lat': 45.0, 'lon': -100.0},      # Clean rural
    {'name': 'Urban', 'lat': 40.7, 'lon': -74.0},       # Urban pollution
    {'name': 'Desert', 'lat': 25.0, 'lon': 55.0},       # Desert dust
]

times = pd.date_range('2023-01-01', '2023-12-31', freq='MS')

print("Monthly Linke turbidity values:")
print(f"{'Month':<10}", end='')
for loc in locations:
    print(f"{loc['name']:<8}", end='')
print()

for i, time in enumerate(times):
    print(f"{time.strftime('%b'):<10}", end='')
    for loc in locations:
        try:
            lt = clearsky.lookup_linke_turbidity(
                pd.DatetimeIndex([time]), 
                loc['lat'], 
                loc['lon']
            )
            print(f"{lt.iloc[0]:<8.2f}", end='')
        except:
            print(f"{'N/A':<8}", end='')
    print()

Install with Tessl CLI

npx tessl i tessl/pypi-pvlib

docs

atmosphere.md

bifacial.md

clearsky.md

iam.md

index.md

inverter.md

iotools.md

irradiance.md

losses.md

pvsystem.md

solar-position.md

spectrum.md

temperature.md

tile.json