|
| 1 | +# Solar Position Plugin Documentation {#SolarPositionDoc} |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +The Solar Position plugin provides comprehensive solar position calculations and sun angle modeling for PyHelios. This plugin enables accurate solar geometry computations essential for radiation modeling, energy balance calculations, and photosynthesis simulations in plant canopy models. |
| 6 | + |
| 7 | +Key features include: |
| 8 | +- Precise solar position calculations based on date, time, and geographic location |
| 9 | +- Sun direction vector computations for ray tracing applications |
| 10 | +- Solar flux calculations with atmospheric corrections |
| 11 | +- Sunrise and sunset time calculations |
| 12 | +- Atmospheric parameter calibration from time series data |
| 13 | + |
| 14 | +## System Requirements |
| 15 | + |
| 16 | +- **Platforms**: Windows, Linux, macOS |
| 17 | +- **Dependencies**: None (uses standard mathematical functions) |
| 18 | +- **GPU**: Not required |
| 19 | +- **Memory**: Minimal memory footprint |
| 20 | + |
| 21 | +## Installation |
| 22 | + |
| 23 | +### Build with Solar Position Plugin |
| 24 | + |
| 25 | +The Solar Position plugin is included in the default PyHelios build. If building explicitly: |
| 26 | + |
| 27 | +```bash |
| 28 | +# Using interactive selection |
| 29 | +build_scripts/build_helios --interactive |
| 30 | + |
| 31 | +# Explicit selection |
| 32 | +build_scripts/build_helios --plugins solarposition |
| 33 | + |
| 34 | +# Check if available |
| 35 | +python -c "from pyhelios.plugins.registry import PluginRegistry; print('solarposition available:', PluginRegistry().is_plugin_available('solarposition'))" |
| 36 | +``` |
| 37 | + |
| 38 | +## Quick Start |
| 39 | + |
| 40 | +```python |
| 41 | +from pyhelios import Context, SolarPosition |
| 42 | + |
| 43 | +# Create context and solar position calculator |
| 44 | +with Context() as context: |
| 45 | + # Set date and time |
| 46 | + context.setDate(year=2024, month=6, day=21) # Summer solstice |
| 47 | + context.setTime(hour=12, minute=0, second=0) # Noon |
| 48 | + |
| 49 | + # Create solar position calculator with coordinates (NYC) |
| 50 | + with SolarPosition(context, utc_offset=-5, latitude=40.7128, longitude=-74.0060) as solar: |
| 51 | + # Get sun elevation angle |
| 52 | + elevation = solar.getSunElevation() |
| 53 | + print(f"Sun elevation: {elevation:.2f} degrees") |
| 54 | + |
| 55 | + # Get sun direction vector |
| 56 | + direction = solar.getSunDirectionVector() |
| 57 | + print(f"Sun direction: ({direction.x:.3f}, {direction.y:.3f}, {direction.z:.3f})") |
| 58 | + |
| 59 | + # Calculate solar flux (standard atmospheric conditions) |
| 60 | + flux = solar.getSolarFlux(pressure_Pa=101325, temperature_K=288.15, |
| 61 | + humidity_rel=0.6, turbidity=0.1) |
| 62 | + print(f"Solar flux: {flux:.2f} W/m²") |
| 63 | +``` |
| 64 | + |
| 65 | +## Examples |
| 66 | + |
| 67 | +### Daily Solar Path Analysis |
| 68 | + |
| 69 | +```python |
| 70 | +from pyhelios import Context, SolarPosition |
| 71 | +import numpy as np |
| 72 | +import matplotlib.pyplot as plt |
| 73 | + |
| 74 | +with Context() as context: |
| 75 | + context.setDate(year=2024, month=6, day=21) # Summer solstice |
| 76 | + |
| 77 | + # Create solar position with coordinates (Davis, CA) |
| 78 | + with SolarPosition(context, utc_offset=-8, latitude=38.5382, longitude=-121.7617) as solar: |
| 79 | + # Calculate sun path throughout the day |
| 80 | + hours = np.arange(5, 20, 0.5) # 5 AM to 8 PM |
| 81 | + elevations = [] |
| 82 | + azimuths = [] |
| 83 | + |
| 84 | + for hour in hours: |
| 85 | + hour_int = int(hour) |
| 86 | + minute_int = int((hour - hour_int) * 60) |
| 87 | + context.setTime(hour=hour_int, minute=minute_int, second=0) |
| 88 | + |
| 89 | + elevation = solar.getSunElevation() |
| 90 | + azimuth = solar.getSunAzimuth() |
| 91 | + |
| 92 | + if elevation > 0: # Sun above horizon |
| 93 | + elevations.append(elevation) |
| 94 | + azimuths.append(azimuth) |
| 95 | + |
| 96 | + # Plot solar path |
| 97 | + plt.figure(figsize=(10, 6)) |
| 98 | + plt.subplot(1, 2, 1) |
| 99 | + plt.plot(hours[:len(elevations)], elevations) |
| 100 | + plt.xlabel('Hour of Day') |
| 101 | + plt.ylabel('Sun Elevation (degrees)') |
| 102 | + plt.title('Sun Elevation vs Time') |
| 103 | + |
| 104 | + plt.subplot(1, 2, 2) |
| 105 | + plt.plot(azimuths, elevations) |
| 106 | + plt.xlabel('Sun Azimuth (degrees)') |
| 107 | + plt.ylabel('Sun Elevation (degrees)') |
| 108 | + plt.title('Sun Path (Elevation vs Azimuth)') |
| 109 | + plt.show() |
| 110 | +``` |
| 111 | + |
| 112 | +### Solar Flux Analysis |
| 113 | + |
| 114 | +```python |
| 115 | +from pyhelios import Context, SolarPosition |
| 116 | + |
| 117 | +def analyze_solar_flux(latitude, longitude, year, month, day): |
| 118 | + """Analyze solar flux variation throughout a day.""" |
| 119 | + |
| 120 | + with Context() as context: |
| 121 | + context.setDate(year=year, month=month, day=day) |
| 122 | + |
| 123 | + # Create solar position with provided coordinates |
| 124 | + with SolarPosition(context, utc_offset=0, latitude=latitude, longitude=longitude) as solar: |
| 125 | + # Get sunrise/sunset times |
| 126 | + sunrise = solar.getSunriseTime() |
| 127 | + sunset = solar.getSunsetTime() |
| 128 | + |
| 129 | + print(f"Sunrise: {sunrise}") |
| 130 | + print(f"Sunset: {sunset}") |
| 131 | + # Calculate day length in hours |
| 132 | + day_length = (sunset.hour * 3600 + sunset.minute * 60 + sunset.second) - (sunrise.hour * 3600 + sunrise.minute * 60 + sunrise.second) |
| 133 | + print(f"Day length: {day_length / 3600:.2f} hours") |
| 134 | + |
| 135 | + # Calculate solar flux at key times |
| 136 | + key_times = [ |
| 137 | + (sunrise.hour, sunrise.minute, 'Sunrise'), |
| 138 | + (12, 0, 'Noon'), |
| 139 | + (sunset.hour, sunset.minute, 'Sunset') |
| 140 | + ] |
| 141 | + |
| 142 | + for hour, minute, label in key_times: |
| 143 | + context.setTime(hour=hour, minute=minute, second=0) |
| 144 | + |
| 145 | + elevation = solar.getSunElevation() |
| 146 | + flux = solar.getSolarFlux(pressure_Pa=101325, temperature_K=288.15, |
| 147 | + humidity_rel=0.6, turbidity=0.1) |
| 148 | + |
| 149 | + print(f"{label}: Elevation = {elevation:.1f}°, Flux = {flux:.0f} W/m²") |
| 150 | + |
| 151 | +# Example usage |
| 152 | +analyze_solar_flux(40.7128, -74.0060, 2024, 6, 21) # NYC summer solstice |
| 153 | +analyze_solar_flux(40.7128, -74.0060, 2024, 12, 21) # NYC winter solstice |
| 154 | +``` |
| 155 | + |
| 156 | +### Error Handling |
| 157 | + |
| 158 | +```python |
| 159 | +from pyhelios import Context, SolarPosition, SolarPositionError |
| 160 | + |
| 161 | +with Context() as context: |
| 162 | + try: |
| 163 | + # This will fail if coordinates not provided |
| 164 | + context.setDate(year=2024, month=7, day=15) |
| 165 | + context.setTime(hour=12, minute=0, second=0) |
| 166 | + with SolarPosition(context) as solar: |
| 167 | + elevation = solar.getSunElevation() |
| 168 | + |
| 169 | + except SolarPositionError as e: |
| 170 | + print(f"Solar position error: {e}") |
| 171 | + # Error messages include specific requirements |
| 172 | + |
| 173 | + # Retry with coordinates |
| 174 | + with SolarPosition(context, utc_offset=-8, latitude=40.0, longitude=-120.0) as solar: |
| 175 | + elevation = solar.getSunElevation() |
| 176 | + print(f"Sun elevation: {elevation:.2f}°") |
| 177 | +``` |
| 178 | + |
| 179 | +## Algorithm Details |
| 180 | + |
| 181 | +The Solar Position plugin implements standard solar geometry algorithms: |
| 182 | + |
| 183 | +- **Solar declination**: Based on day of year using standard astronomical formulas |
| 184 | +- **Hour angle**: Calculated from local solar time and longitude |
| 185 | +- **Solar elevation/azimuth**: Standard spherical trigonometry calculations |
| 186 | +- **Atmospheric corrections**: Air mass calculations for solar flux attenuation |
| 187 | +- **Time calculations**: Sunrise/sunset based on solar elevation = 0° with refraction correction |
| 188 | + |
| 189 | +These implementations follow established solar engineering practices and produce results accurate to within 0.1° for typical applications. |
0 commit comments