"""Configuration constants and default parameters for Solar Intelligence.""" from __future__ import annotations import logging from datetime import datetime from pathlib import Path logger = logging.getLogger(__name__) # --------------------------------------------------------------------------- # Paths # --------------------------------------------------------------------------- PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent DATA_DIR = PROJECT_ROOT / "data" CACHE_DIR = DATA_DIR / "cache" CACHE_DIR.mkdir(parents=True, exist_ok=True) # --------------------------------------------------------------------------- # NASA POWER API # --------------------------------------------------------------------------- NASA_POWER_BASE_URL = "https://power.larc.nasa.gov/api/temporal" NASA_POWER_SOLAR_PARAMS = [ "ALLSKY_SFC_SW_DWN", # GHI — All Sky Surface Shortwave Downward Irradiance (kWh/m²/day) "CLRSKY_SFC_SW_DWN", # Clear Sky GHI "ALLSKY_SFC_SW_DNI", # DNI — Direct Normal Irradiance "ALLSKY_SFC_SW_DIFF", # DHI — Diffuse Horizontal Irradiance "ALLSKY_KT", # Clearness Index "T2M", # Temperature at 2m (°C) "T2M_MAX", # Max daily temperature "T2M_MIN", # Min daily temperature "WS2M", # Wind speed at 2m (m/s) "RH2M", # Relative humidity at 2m (%) ] NASA_POWER_COMMUNITIES = { "renewable_energy": "RE", "sustainable_buildings": "SB", "agroclimatology": "AG", } # Cache TTL in days CACHE_TTL_DAYS = 30 # --------------------------------------------------------------------------- # ERA5 (Copernicus Climate Data Store) API # --------------------------------------------------------------------------- ERA5_CDS_URL = "https://cds.climate.copernicus.eu/api" ERA5_SOLAR_VARIABLES = [ "surface_solar_radiation_downwards", # ssrd — GHI (J/m2 cumulative) "total_sky_direct_solar_radiation_at_surface", # fdir — DNI (J/m2 cumulative) "2m_temperature", # t2m (K) "10m_u_component_of_wind", # u10 (m/s) "10m_v_component_of_wind", # v10 (m/s) "2m_dewpoint_temperature", # d2m (K) "total_cloud_cover", # tcc (0-1) "surface_pressure", # sp (Pa) ] ERA5_DATASET_NAME = "reanalysis-era5-single-levels" # ERA5 variable name -> standard name mapping ERA5_VAR_MAP = { "ssrd": "ALLSKY_SFC_SW_DWN", "fdir": "ALLSKY_SFC_SW_DNI", "t2m": "T2M", "u10": "WS2M", # will combine u10+v10 into wind speed "v10": "WS2M_v", # helper for wind speed calc "d2m": "DEWPOINT", "tcc": "CLOUD_COVER", "sp": "PRESSURE", } # --------------------------------------------------------------------------- # Default Solar Panel Specifications # --------------------------------------------------------------------------- DEFAULT_PANEL_EFFICIENCY = 0.20 # 20% — typical monocrystalline DEFAULT_PANEL_AREA = 1.7 # m² — standard 60-cell panel DEFAULT_NUM_PANELS = 10 DEFAULT_SYSTEM_LOSSES = 0.14 # 14% — wiring, soiling, mismatch DEFAULT_INVERTER_EFFICIENCY = 0.96 # 96% DEFAULT_TEMP_COEFFICIENT = -0.004 # -0.4%/°C (power temperature coefficient) DEFAULT_NOCT = 45 # °C — Nominal Operating Cell Temperature DEFAULT_STC_TEMP = 25 # °C — Standard Test Conditions temperature DEFAULT_ALBEDO = 0.25 # Ground surface reflectance (grass) # --------------------------------------------------------------------------- # Solar Panel Orientations # --------------------------------------------------------------------------- ORIENTATIONS = { "North": 0, "North-East": 45, "East": 90, "South-East": 135, "South": 180, "South-West": 225, "West": 270, "North-West": 315, } DEFAULT_TILT_ANGLES = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90] # --------------------------------------------------------------------------- # Currency Settings # --------------------------------------------------------------------------- CURRENCIES = { "INR": {"symbol": "₹", "name": "Indian Rupee", "locale": "en_IN"}, "USD": {"symbol": "$", "name": "US Dollar", "locale": "en_US"}, "EUR": {"symbol": "€", "name": "Euro", "locale": "en_EU"}, "GBP": {"symbol": "£", "name": "British Pound", "locale": "en_GB"}, "CNY": {"symbol": "¥", "name": "Chinese Yuan", "locale": "zh_CN"}, "JPY": {"symbol": "¥", "name": "Japanese Yen", "locale": "ja_JP"}, "AUD": {"symbol": "A$", "name": "Australian Dollar", "locale": "en_AU"}, "BRL": {"symbol": "R$", "name": "Brazilian Real", "locale": "pt_BR"}, "ZAR": {"symbol": "R", "name": "South African Rand", "locale": "en_ZA"}, "CAD": {"symbol": "C$", "name": "Canadian Dollar", "locale": "en_CA"}, "KRW": {"symbol": "₩", "name": "South Korean Won", "locale": "ko_KR"}, "AED": {"symbol": "د.إ", "name": "UAE Dirham", "locale": "ar_AE"}, "MXN": {"symbol": "$", "name": "Mexican Peso", "locale": "es_MX"}, "SGD": {"symbol": "S$", "name": "Singapore Dollar", "locale": "en_SG"}, } # Defaults per currency CURRENCY_DEFAULTS = { "INR": { "system_cost": 500000, # ₹5 lakh for 3kW system "electricity_rate": 8.0, # ₹8/kWh "maintenance_cost": 5000, # ₹5000/year "incentive_percent": 0.40, # 40% MNRE subsidy "rate_increase": 0.05, # 5% annual increase }, "USD": { "system_cost": 15000, "electricity_rate": 0.12, "maintenance_cost": 200, "incentive_percent": 0.30, # 30% ITC "rate_increase": 0.03, }, "EUR": { "system_cost": 12000, "electricity_rate": 0.30, "maintenance_cost": 150, "incentive_percent": 0.20, "rate_increase": 0.03, }, "GBP": { "system_cost": 10000, "electricity_rate": 0.28, "maintenance_cost": 120, "incentive_percent": 0.00, # No direct subsidy (SEG payments instead) "rate_increase": 0.04, }, "CNY": { "system_cost": 35000, # ~¥35,000 for 3kW system "electricity_rate": 0.55, "maintenance_cost": 800, "incentive_percent": 0.15, "rate_increase": 0.03, }, "JPY": { "system_cost": 1050000, # ~¥1,050,000 for 3kW system "electricity_rate": 30.0, "maintenance_cost": 25000, "incentive_percent": 0.10, "rate_increase": 0.02, }, "AUD": { "system_cost": 8000, "electricity_rate": 0.30, "maintenance_cost": 200, "incentive_percent": 0.30, # SRES rebate "rate_increase": 0.04, }, "BRL": { "system_cost": 25000, # R$25,000 for 3kW system "electricity_rate": 0.80, "maintenance_cost": 500, "incentive_percent": 0.00, "rate_increase": 0.06, }, "ZAR": { "system_cost": 90000, # R90,000 for 3kW system "electricity_rate": 2.50, "maintenance_cost": 2000, "incentive_percent": 0.25, "rate_increase": 0.08, }, "CAD": { "system_cost": 12000, "electricity_rate": 0.13, "maintenance_cost": 200, "incentive_percent": 0.25, "rate_increase": 0.03, }, "KRW": { "system_cost": 5000000, # ₩5,000,000 for 3kW system "electricity_rate": 120.0, "maintenance_cost": 100000, "incentive_percent": 0.30, "rate_increase": 0.03, }, "AED": { "system_cost": 20000, "electricity_rate": 0.29, "maintenance_cost": 500, "incentive_percent": 0.00, "rate_increase": 0.02, }, "MXN": { "system_cost": 120000, # MX$120,000 for 3kW system "electricity_rate": 1.50, "maintenance_cost": 3000, "incentive_percent": 0.00, "rate_increase": 0.05, }, "SGD": { "system_cost": 10000, "electricity_rate": 0.25, "maintenance_cost": 200, "incentive_percent": 0.00, "rate_increase": 0.02, }, } DEFAULT_CURRENCY = "INR" # --------------------------------------------------------------------------- # Financial Defaults (use INR as default) # --------------------------------------------------------------------------- DEFAULT_SYSTEM_COST = CURRENCY_DEFAULTS[DEFAULT_CURRENCY]["system_cost"] DEFAULT_ELECTRICITY_RATE = CURRENCY_DEFAULTS[DEFAULT_CURRENCY]["electricity_rate"] DEFAULT_RATE_INCREASE = CURRENCY_DEFAULTS[DEFAULT_CURRENCY]["rate_increase"] DEFAULT_INCENTIVE_PERCENT = CURRENCY_DEFAULTS[DEFAULT_CURRENCY]["incentive_percent"] DEFAULT_MAINTENANCE_COST = CURRENCY_DEFAULTS[DEFAULT_CURRENCY]["maintenance_cost"] DEFAULT_PANEL_DEGRADATION = 0.005 # 0.5%/year DEFAULT_SYSTEM_LIFETIME = 25 # years # --------------------------------------------------------------------------- # Carbon & Environmental # --------------------------------------------------------------------------- CARBON_FACTOR_KG_PER_KWH = 0.42 # kg CO2 per kWh (US grid average) TREES_KG_CO2_PER_YEAR = 22 # kg CO2 absorbed per tree per year CAR_KG_CO2_PER_MILE = 0.404 # kg CO2 per mile driven # --------------------------------------------------------------------------- # Visualization # --------------------------------------------------------------------------- SOLAR_CMAP = "YlOrRd" IRRADIANCE_CMAP = "inferno" ENERGY_CMAP = "viridis" COMPARISON_CMAP = "Category10" ANOMALY_CMAP = "RdBu_r" # Global irradiance reference ranges (kWh/m²/day) IRRADIANCE_EXCELLENT = 6.0 # Sahara, Middle East, Australia IRRADIANCE_GOOD = 4.5 # Southern US, Mediterranean IRRADIANCE_MODERATE = 3.0 # Northern US, Central Europe IRRADIANCE_LOW = 1.5 # Scandinavia, UK winter # --------------------------------------------------------------------------- # Country-Specific Carbon Emission Factors (kg CO2 per kWh) # Source: IEA Emissions Factors (2023 edition) # --------------------------------------------------------------------------- COUNTRY_CARBON_FACTORS: dict[str, float] = { "IN": 0.82, # India "US": 0.42, # United States "DE": 0.35, # Germany "FR": 0.06, # France (nuclear-heavy) "GB": 0.23, # United Kingdom "CN": 0.58, # China "JP": 0.47, # Japan "BR": 0.07, # Brazil (hydro-heavy) "AU": 0.66, # Australia "ZA": 0.93, # South Africa (coal-heavy) "CA": 0.12, # Canada (hydro-heavy) "IT": 0.33, # Italy "ES": 0.22, # Spain "KR": 0.46, # South Korea "MX": 0.43, # Mexico "SA": 0.62, # Saudi Arabia "AE": 0.42, # UAE "EG": 0.47, # Egypt "NG": 0.43, # Nigeria "KE": 0.03, # Kenya (geothermal-heavy) "TR": 0.41, # Turkey "TH": 0.49, # Thailand "ID": 0.72, # Indonesia "PK": 0.49, # Pakistan "BD": 0.60, # Bangladesh "VN": 0.52, # Vietnam "PH": 0.61, # Philippines "RU": 0.33, # Russia "NL": 0.33, # Netherlands "SE": 0.01, # Sweden (nuclear + hydro) "NO": 0.01, # Norway (hydro-heavy) "PL": 0.66, # Poland (coal-heavy) "AR": 0.31, # Argentina "CL": 0.35, # Chile "CO": 0.16, # Colombia (hydro-heavy) } _DEFAULT_CARBON_FACTOR = 0.42 # World average fallback def get_carbon_factor(country_code: str) -> float: """Return carbon emission factor for a country, with fallback to world average.""" return COUNTRY_CARBON_FACTORS.get(country_code.upper(), _DEFAULT_CARBON_FACTOR) # --------------------------------------------------------------------------- # Named Constants (replace magic numbers throughout codebase) # --------------------------------------------------------------------------- PEAK_SUN_HOURS_APPROX = 5.0 # Average peak sun hours per day MAX_IRRADIANCE_W_M2 = 1400 # Maximum solar irradiance at Earth surface (W/m2) MIN_TEMP_FACTOR = 0.5 # Minimum temperature correction factor MAX_TEMP_FACTOR = 1.2 # Maximum temperature correction factor NOCT_REFERENCE_IRRADIANCE = 800 # W/m2 — NOCT reference irradiance NOCT_REFERENCE_TEMP = 20 # deg C — NOCT reference ambient temperature # --------------------------------------------------------------------------- # Dynamic Date Range (auto-update each year) # --------------------------------------------------------------------------- def default_end_year() -> int: """Return the last complete calendar year for data queries.""" return datetime.now().year - 1 def default_start_year() -> int: """Return 3 years before the end year for a 4-year analysis window.""" return default_end_year() - 3 DEFAULT_START_YEAR = default_start_year() DEFAULT_END_YEAR = default_end_year() # --------------------------------------------------------------------------- # Colorblind-Friendly Palette (Okabe-Ito) # --------------------------------------------------------------------------- CB_PALETTE = [ "#0072B2", # blue "#E69F00", # orange "#009E73", # green "#CC79A7", # pink "#D55E00", # vermillion "#56B4E9", # sky blue "#F0E442", # yellow "#000000", # black ] CB_SOLAR_CMAP = "cividis" CB_IRRADIANCE_CMAP = "viridis" # --------------------------------------------------------------------------- # Default Appliance Wattages (kW) # --------------------------------------------------------------------------- DEFAULT_APPLIANCE_WATTAGES: dict[str, float] = { "air_conditioner": 1.5, "central_ac": 3.5, "refrigerator": 0.15, "washing_machine": 0.5, "water_heater": 2.0, "led_light": 0.01, "ceiling_fan": 0.075, "ev_charger_l2": 7.4, "microwave": 1.2, "laptop": 0.065, "television": 0.1, "iron": 1.0, "hair_dryer": 1.5, } # --------------------------------------------------------------------------- # Payback Period Thresholds (years) by Region # --------------------------------------------------------------------------- PAYBACK_THRESHOLDS: dict[str, dict[str, int]] = { "default": {"excellent": 5, "very_good": 8, "good": 12, "moderate": 20}, "IN": {"excellent": 4, "very_good": 6, "good": 8, "moderate": 12}, "DE": {"excellent": 7, "very_good": 10, "good": 14, "moderate": 20}, } # --------------------------------------------------------------------------- # Country Profiles (currency, carbon, electricity, subsidies) # --------------------------------------------------------------------------- COUNTRY_PROFILES: dict[str, dict] = { "IN": { "default_currency": "INR", "carbon_factor": 0.82, "electricity_rate": 8.0, "subsidy_percent": 0.40, "subsidy_type": "Central Financial Assistance (MNRE)", }, "US": { "default_currency": "USD", "carbon_factor": 0.42, "electricity_rate": 0.12, "subsidy_percent": 0.30, "subsidy_type": "Investment Tax Credit (ITC)", }, "DE": { "default_currency": "EUR", "carbon_factor": 0.35, "electricity_rate": 0.30, "subsidy_percent": 0.20, "subsidy_type": "Feed-in Tariff (EEG)", }, "FR": { "default_currency": "EUR", "carbon_factor": 0.06, "electricity_rate": 0.22, "subsidy_percent": 0.25, "subsidy_type": "Feed-in Premium + Tax Credit", }, "GB": { "default_currency": "GBP", "carbon_factor": 0.23, "electricity_rate": 0.28, "subsidy_percent": 0.00, "subsidy_type": "Smart Export Guarantee (SEG)", }, "CN": { "default_currency": "CNY", "carbon_factor": 0.58, "electricity_rate": 0.55, "subsidy_percent": 0.15, "subsidy_type": "Provincial Feed-in Tariff", }, "JP": { "default_currency": "JPY", "carbon_factor": 0.47, "electricity_rate": 30.0, "subsidy_percent": 0.10, "subsidy_type": "Feed-in Tariff (FIT)", }, "BR": { "default_currency": "BRL", "carbon_factor": 0.07, "electricity_rate": 0.80, "subsidy_percent": 0.00, "subsidy_type": "Net Metering", }, "AU": { "default_currency": "AUD", "carbon_factor": 0.66, "electricity_rate": 0.30, "subsidy_percent": 0.30, "subsidy_type": "Small-scale Renewable Energy Scheme (SRES)", }, "ZA": { "default_currency": "ZAR", "carbon_factor": 0.93, "electricity_rate": 2.50, "subsidy_percent": 0.25, "subsidy_type": "Section 12B Tax Deduction", }, "CA": { "default_currency": "CAD", "carbon_factor": 0.12, "electricity_rate": 0.13, "subsidy_percent": 0.25, "subsidy_type": "Canada Greener Homes Grant", }, "KR": { "default_currency": "KRW", "carbon_factor": 0.46, "electricity_rate": 120.0, "subsidy_percent": 0.30, "subsidy_type": "Renewable Portfolio Standard (RPS)", }, "MX": { "default_currency": "MXN", "carbon_factor": 0.43, "electricity_rate": 1.50, "subsidy_percent": 0.00, "subsidy_type": "Net Metering", }, "AE": { "default_currency": "AED", "carbon_factor": 0.42, "electricity_rate": 0.29, "subsidy_percent": 0.00, "subsidy_type": "Shams Dubai Net Metering", }, "ES": { "default_currency": "EUR", "carbon_factor": 0.22, "electricity_rate": 0.25, "subsidy_percent": 0.40, "subsidy_type": "EU NextGen Funds + Self-Consumption Bonus", }, }