solarseg / efficiency_aware_density.py
0x1ay's picture
Sync all changes: demo dataset, quality tiers, confidence scoring, zoom fix, import fix
2d62fcb
"""
Custom power density calculation using efficiency model.
Calculates site-specific power density based on latitude and longitude.
"""
import os
import sys
from pathlib import Path
import numpy as np
from typing import Optional, Tuple
# Path to efficiency_model directory (used in _load_interpolator)
EFFICIENCY_MODEL_PATH = Path(__file__).parent / "efficiency_model"
# Default power densities (baseline kWp/m²)
DEFAULT_POWER_DENSITY = 0.18 # Standard baseline
POWER_DENSITY_RANGE = (0.101, 0.17) # Expected operating range when lookup is available
class EfficencyAwarePowerDensity:
"""
Calculate site-specific power density based on solar efficiency.
Uses the efficiency model to adjust power density for geographic location.
"""
def __init__(self, efficiency_model=None):
"""
Initialize with optional pre-loaded efficiency model.
Args:
efficiency_model: Optional pre-loaded SolarEnergyInterpolator instance
"""
self.interpolator = efficiency_model
self._load_interpolator()
def _load_interpolator(self):
"""Lazy load the efficiency model interpolator"""
if self.interpolator is not None:
return
try:
# Add efficiency_model to sys.path temporarily
import sys
model_path_str = str(EFFICIENCY_MODEL_PATH)
if model_path_str not in sys.path:
sys.path.insert(0, model_path_str)
# Import and initialize with data directory path (no cwd change needed)
from efficiencyMap import SolarEnergyInterpolator
self.interpolator = SolarEnergyInterpolator(data_dir=model_path_str)
except Exception as e:
print(f"Warning: Could not load efficiency model: {str(e)}")
import traceback
traceback.print_exc()
self.interpolator = None
def get_efficiency(self, latitude: float, longitude: float) -> float:
"""
Get solar efficiency for a location.
Args:
latitude: Site latitude (-60 to 65)
longitude: Site longitude (-180 to 180)
Returns:
float: Solar efficiency as percentage (0-100) or 0 if unavailable
"""
# Ensure interpolator is loaded
if self.interpolator is None:
self._load_interpolator()
if self.interpolator is None:
return 0
try:
efficiency = self.interpolator.get_solar_efficiency(latitude, longitude)
return float(efficiency) if efficiency and efficiency > 0 else 0
except Exception as e:
print(f"Warning: Efficiency calculation failed for ({latitude}, {longitude}): {str(e)}")
return 0
def calculate_power_density(self, latitude: float, longitude: float,
baseline_density: float = DEFAULT_POWER_DENSITY) -> float:
"""
Calculate site-specific power density based on solar efficiency.
High efficiency areas (e.g., deserts) → Higher power density
Low efficiency areas (e.g., cloudy regions) → Lower power density
Args:
latitude: Site latitude
longitude: Site longitude
baseline_density: Baseline power density in kWp/m² (default: 0.18)
Returns:
float: Site-specific power density in kWp/m²
"""
# Get efficiency (0-100%)
efficiency = self.get_efficiency(latitude, longitude)
if efficiency == 0:
# Use baseline if efficiency model unavailable
return baseline_density
# Map the efficiency percentage directly into the calibrated power-density band.
adjusted_density = efficiency / 100.0
# Clamp to the expected operating range.
adjusted_density = np.clip(adjusted_density, POWER_DENSITY_RANGE[0], POWER_DENSITY_RANGE[1])
return round(adjusted_density, 4)
def get_site_power_density_info(self, latitude: float, longitude: float,
baseline_density: float = DEFAULT_POWER_DENSITY) -> dict:
"""
Get comprehensive power density information for a site.
Args:
latitude: Site latitude
longitude: Site longitude
baseline_density: Baseline power density
Returns:
dict: Power density information including efficiency and adjusted value
"""
efficiency = self.get_efficiency(latitude, longitude)
adjusted_density = self.calculate_power_density(latitude, longitude, baseline_density)
return {
'efficiency_percent': efficiency,
'baseline_density_kwp_m2': baseline_density,
'adjusted_density_kwp_m2': adjusted_density,
'density_adjustment_factor': adjusted_density / baseline_density if baseline_density > 0 else 1.0,
'location': f"{latitude:.4f}°, {longitude:.4f}°"
}
# Initialize global instance
try:
power_density_calculator = EfficencyAwarePowerDensity()
except Exception as e:
print(f"Warning: Could not initialize power density calculator: {str(e)}")
power_density_calculator = None
def get_power_density_for_site(latitude: float, longitude: float,
baseline_density: float = DEFAULT_POWER_DENSITY) -> float:
"""
Convenience function to get power density for a site.
Args:
latitude: Site latitude
longitude: Site longitude
baseline_density: Baseline power density (default: 0.18 kWp/m²)
Returns:
float: Site-specific power density in kWp/m²
"""
# Create fresh instance to ensure no caching issues
try:
calculator = EfficencyAwarePowerDensity()
return calculator.calculate_power_density(latitude, longitude, baseline_density)
except Exception as e:
print(f"Error calculating power density: {str(e)}")
return baseline_density
def get_power_density_info(latitude: float, longitude: float,
baseline_density: float = DEFAULT_POWER_DENSITY) -> dict:
"""
Convenience function to get detailed power density information.
Args:
latitude: Site latitude
longitude: Site longitude
baseline_density: Baseline power density
Returns:
dict: Detailed power density information
"""
# Create fresh instance to ensure no caching issues
try:
calculator = EfficencyAwarePowerDensity()
return calculator.get_site_power_density_info(latitude, longitude, baseline_density)
except Exception as e:
print(f"Error getting power density info: {str(e)}")
return {
'efficiency_percent': 0,
'baseline_density_kwp_m2': baseline_density,
'adjusted_density_kwp_m2': baseline_density,
'density_adjustment_factor': 1.0,
'location': f"{latitude:.4f}°, {longitude:.4f}°"
}