| from __future__ import annotations |
|
|
| from .evidence import make_evidence |
| from .models import EvidenceItem |
|
|
|
|
| def summarize_sun_wind(lat: float, lon: float, wind_direction_deg: float | None = None) -> tuple[dict[str, str], list[EvidenceItem]]: |
| hemisphere = "northern" if lat >= 0 else "southern" |
| sun_side = "southern" if lat >= 0 else "northern" |
| wind_text = _wind_text(wind_direction_deg) |
| summary = { |
| "hemisphere": hemisphere, |
| "sun_side": sun_side, |
| "orientation_note": ( |
| f"At this latitude in the {hemisphere} hemisphere, the sun is generally biased toward the {sun_side} side of the sky across much of the year." |
| ), |
| "east_west_note": "Morning exposure is generally from the east; afternoon heat/glare risk is generally stronger from the west.", |
| "wind_note": wind_text, |
| "limitation": "This is a deterministic orientation summary and does not model shadows from surrounding buildings or terrain.", |
| } |
| evidence = [ |
| make_evidence( |
| category="Sun/wind", |
| finding="A deterministic sun/orientation summary was computed from latitude and longitude.", |
| source_name="Local solar/orientation calculation", |
| source_url="", |
| source_type="computed", |
| resolution_or_scope="anchor coordinate", |
| confidence="medium", |
| limitation="Does not model site obstructions, surrounding-building shadows, or microclimate.", |
| design_implication="Use for early massing, shading, and facade-orientation thinking.", |
| verification_needed="Observe actual shade, adjacent heights, glare, and wind during site visit.", |
| output_label="computed", |
| ) |
| ] |
| return summary, evidence |
|
|
|
|
| def _wind_text(direction: float | None) -> str: |
| if direction is None: |
| return "Wind direction was not available from climate data." |
| return f"Available climate data suggests dominant wind around {round(direction)} degrees ({_bearing_label(direction)}). Treat this as regional/modelled." |
|
|
|
|
| def _bearing_label(deg: float) -> str: |
| labels = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"] |
| return labels[int((deg + 22.5) // 45) % 8] |
|
|