Solar Radiation Algorithms¶
Overview¶
Solar radiation is the primary energy input driving all Critical Zone processes. The EEMT framework uses the GRASS GIS r.sun module with multi-threaded processing (nprocs parameter) to calculate topographically-modified solar radiation, accounting for slope, aspect, atmospheric conditions, and terrain shadowing effects.
Mathematical Foundation¶
Clear-Sky Solar Radiation¶
The theoretical maximum solar radiation reaching Earth's atmosphere is determined by:
Where: - I₀ = Extraterrestrial radiation [W m⁻²] - Sc = Solar constant (1367 W m⁻²) - r₀/r = Earth-Sun distance ratio (varies seasonally)
Atmospheric Attenuation¶
Solar radiation is attenuated as it passes through the atmosphere. The EEMT framework uses the Linke Turbidity Factor to account for atmospheric effects:
Where: - TL = Linke turbidity factor [dimensionless] - δatm = Optical thickness of real atmosphere - δclean = Optical thickness of clean, dry atmosphere
Typical Linke turbidity values: - 1.0-2.0: Very clean, cold air (Arctic, high mountains) - 2.0-3.0: Clean air (rural areas, moderate elevations) - 3.0-4.0: Moderate turbidity (temperate regions) - 4.0-5.0: Turbid atmosphere (urban, humid areas) - 5.0-8.0: Very turbid (polluted urban, tropical)
Core Algorithm: r.sun¶
Algorithm Components¶
The r.sun module calculates solar radiation using three primary components:
1. Direct (Beam) Radiation¶
Direct radiation reaching a tilted surface:
Where: - τb = Beam transmittance through atmosphere - θi = Angle of incidence between sun rays and surface normal
The angle of incidence is calculated as:
Where: - β = Surface slope angle [degrees] - Z = Solar zenith angle [degrees] - φs = Solar azimuth [degrees] - φn = Surface aspect [degrees]
2. Diffuse (Sky) Radiation¶
Diffuse radiation from atmospheric scattering:
Where: - τd = Diffuse transmittance - Fsky = Sky view factor (portion of sky visible from surface)
The sky view factor accounts for terrain obstruction:
Where H(φ) is the horizon angle in direction φ.
3. Reflected Radiation¶
Radiation reflected from surrounding terrain:
Where: - ρ = Surface albedo (reflectance) - Fterrain = Terrain view factor
Total Solar Radiation¶
The total radiation received by a surface is:
Horizon Calculation¶
Horizon Effects¶
Terrain shadowing significantly affects solar radiation receipt. The horizon angle determines when direct sunlight is blocked:
Where: - H(φ) = Horizon angle in direction φ - z(d,φ) = Elevation at distance d in direction φ - z₀ = Elevation at calculation point - d = Distance from calculation point
Shadow Calculation¶
A point is in shadow when:
Where: - hsun = Solar elevation angle - H(φsun) = Horizon angle in sun direction
Implementation Details¶
Temporal Resolution¶
The EEMT framework calculates solar radiation at regular time intervals throughout each day:
def calculate_daily_solar(dem, day_of_year, step_minutes=15):
"""
Calculate solar radiation for one day
Parameters:
- dem: Digital elevation model
- day_of_year: Julian day (1-365)
- step_minutes: Time step for calculation (3-60 minutes)
Returns:
- Daily total solar radiation [Wh m⁻²]
"""
# Solar declination
declination = 23.45 * sin(360 * (284 + day_of_year) / 365)
# Calculate sunrise and sunset times
sunrise, sunset = calculate_sun_times(latitude, declination)
# Time loop
total_radiation = 0
for time in range(sunrise, sunset, step_minutes):
# Solar position
zenith, azimuth = solar_position(time, day_of_year, latitude, longitude)
# Check for shadows
if not in_shadow(zenith, azimuth, horizon):
# Calculate radiation components
direct = calculate_direct(zenith, azimuth, slope, aspect)
diffuse = calculate_diffuse(sky_view_factor)
reflected = calculate_reflected(albedo, terrain_view_factor)
# Sum components
instantaneous = direct + diffuse + reflected
# Integrate over time step
total_radiation += instantaneous * (step_minutes * 60) # Convert to seconds
return total_radiation / 3600 # Convert to Wh
Annual Integration¶
Annual solar radiation is calculated by summing daily values:
def calculate_annual_solar(dem, year, step_minutes=15):
"""
Calculate annual solar radiation
Returns:
- Annual solar radiation maps for each day
- Monthly summaries
- Annual total [MJ m⁻² yr⁻¹]
"""
daily_radiation = []
# Calculate for each day
for day in range(1, 366):
daily = calculate_daily_solar(dem, day, step_minutes)
daily_radiation.append(daily)
# Monthly aggregation
monthly_radiation = aggregate_to_monthly(daily_radiation)
# Annual total
annual_total = sum(daily_radiation) * 0.0036 # Convert Wh to MJ
return {
'daily': daily_radiation,
'monthly': monthly_radiation,
'annual': annual_total
}
Parameter Optimization¶
Step Size Selection¶
The time step affects accuracy and computational cost:
| Step Size | Accuracy | Computation Time | Recommended Use |
|---|---|---|---|
| 3 min | Very High | Very Long | Research, small areas |
| 5 min | High | Long | Detailed analysis |
| 10 min | Good | Moderate | Standard analysis |
| 15 min | Adequate | Fast | Large areas |
| 30 min | Low | Very Fast | Preliminary analysis |
Atmospheric Parameters¶
Linke Turbidity Estimation¶
For areas without measurements, estimate Linke turbidity from:
def estimate_linke_turbidity(elevation, latitude, month):
"""
Estimate Linke turbidity factor
Based on Remund et al. (2003) global climatology
"""
# Base turbidity at sea level
if abs(latitude) > 60:
base_turbidity = 2.0 # Polar regions
elif abs(latitude) > 35:
base_turbidity = 3.0 # Temperate regions
else:
base_turbidity = 4.0 # Tropical regions
# Elevation correction (decrease with altitude)
elevation_correction = -0.5 * (elevation / 1000)
# Seasonal variation
seasonal_factor = 1 + 0.3 * sin(2 * pi * (month - 3) / 12)
# Final estimate
linke = base_turbidity + elevation_correction
linke *= seasonal_factor
return max(1.0, min(8.0, linke)) # Constrain to valid range
Surface Albedo Values¶
Typical albedo values for different surfaces:
| Surface Type | Albedo Range | EEMT Default |
|---|---|---|
| Fresh snow | 0.80-0.95 | 0.85 |
| Old snow | 0.40-0.70 | 0.55 |
| Desert sand | 0.30-0.40 | 0.35 |
| Bare soil | 0.15-0.25 | 0.20 |
| Grassland | 0.15-0.25 | 0.20 |
| Forest | 0.10-0.20 | 0.15 |
| Water | 0.05-0.10 | 0.07 |
Topographic Effects¶
Slope and Aspect Modification¶
Radiation varies strongly with topography:
This ratio can range from: - 0.0: Complete shading (north-facing cliffs) - 0.5: Reduced radiation (pole-facing slopes) - 1.0: Same as flat surface - 1.5: Enhanced radiation (equator-facing slopes) - 2.0+: Maximum enhancement (optimal slope/aspect)
Elevation Effects¶
Solar radiation increases with elevation due to:
- Reduced atmospheric path length
- Lower atmospheric turbidity
- Decreased water vapor content
Approximate increase: +7% per 1000m elevation
Quality Control¶
Validation Checks¶
def validate_solar_output(radiation_map):
"""
Quality control for solar radiation calculations
"""
checks = {
'range': check_physical_limits(radiation_map),
'spatial': check_spatial_consistency(radiation_map),
'temporal': check_temporal_patterns(radiation_map),
'topographic': check_topographic_effects(radiation_map)
}
return checks
def check_physical_limits(radiation):
"""
Ensure radiation values are physically reasonable
"""
# Maximum theoretical clear-sky radiation
max_theoretical = 1367 # W/m² (solar constant)
# Typical annual totals (MJ/m²/yr)
min_annual = 1000 # Polar regions
max_annual = 9000 # Desert regions
return {
'instantaneous_valid': radiation.max() < max_theoretical,
'annual_range_valid': min_annual < radiation.sum() < max_annual
}
Common Issues and Solutions¶
Issue: Unrealistic radiation values¶
Symptoms: Radiation exceeds physical limits or shows artifacts
Solutions: 1. Check DEM units and projection 2. Verify Linke turbidity is appropriate for region 3. Ensure time step is adequate for latitude 4. Check for DEM artifacts or errors
Issue: Edge effects¶
Symptoms: Incorrect radiation near DEM boundaries
Solutions: 1. Buffer DEM by horizon calculation distance 2. Use larger DEM extent than study area 3. Apply edge correction algorithms
Issue: Computational performance¶
Symptoms: Calculations take excessive time
Solutions: 1. Increase time step (reduce from 5 to 15 minutes) 2. Tile large DEMs for parallel processing 3. Use monthly representative days instead of full year 4. Enable GPU acceleration if available
References¶
-
Hofierka, J., & Suri, M. (2002). The solar radiation model for Open source GIS: implementation and applications. Proceedings of the Open source GIS-GRASS users conference.
-
Remund, J., et al. (2003). Worldwide Linke turbidity information. Proceedings of ISES Solar World Congress.
-
Ruiz‐Arias, J. A., et al. (2009). A comparative analysis of DEM‐based models to estimate the solar radiation in mountainous terrain. International Journal of Geographical Information Science, 23(8), 1049-1076.
Next: Climate Integration →