These helpers run client-side and do not call the API. They give the caller a chance to detect configurations that are likely to produce inaccurate results before incurring the wall-time cost of an actual analysis.

SEVERITY_LEVELS module-attribute

Python
SEVERITY_LEVELS: tuple[str, ...] = (
"info",
"ok",
"marginal",
"warning",
"critical",
)

Severity levels in increasing order of concern.

info is reserved for cases where the question does not apply (no positive-elevation hours in the window, or invalid input).

PreflightWarning

Bases: Exception

Raised by an opt-in pre-flight gate when the configuration is unlikely to produce reliable results.

Only raised when a caller explicitly opts in via preflight="raise". The default integration mode is "log" (logger warning, no raise).

SunContextResult

Bases: TypedDict

Structured result returned by estimate_sun_context_loss.

severity instance-attribute

Python
severity: str

One of SEVERITY_LEVELS.

message instance-attribute

Python
message: str

Human-readable explanation suitable for a banner.

min_sun_elevation_deg instance-attribute

Python
min_sun_elevation_deg: Optional[float]

Lowest above-horizon sun elevation reached during the window (degrees). None when no positive-elevation hours were sampled.

min_sun_elevation_month instance-attribute

Python
min_sun_elevation_month: Optional[int]

Month of the worst-case hour. None for sub-horizon or zero-sample windows.

min_sun_elevation_day instance-attribute

Python
min_sun_elevation_day: Optional[int]

Day of the month of the worst-case hour. None for sub-horizon or zero-sample windows.

min_sun_elevation_hour instance-attribute

Python
min_sun_elevation_hour: Optional[int]

Hour of the worst-case hour. None for sub-horizon or zero-sample windows.

pattern instance-attribute

Python
pattern: Optional[str]

Human-readable hemisphere/season/time-band label, e.g. "Northern hemisphere, winter, late morning".

buffer_breakeven_height_m instance-attribute

Python
buffer_breakeven_height_m: float

Tallest building whose full shadow fits inside buffer_m at the worst-case elevation.

shadow_at_typical_building_m instance-attribute

Python
shadow_at_typical_building_m: float

Shadow length of a typical_building_height_m building at the worst-case elevation.

shadow_at_max_building_m instance-attribute

Python
shadow_at_max_building_m: Optional[float]

Shadow length of a max_building_height_m building. None if that argument was not supplied.

estimate_sun_context_loss

Python
estimate_sun_context_loss(
*,
lat: float,
lon: float = 0.0,
timezone_offset_h: Optional[float] = None,
start_month: int,
start_day: int,
start_hour: int,
end_month: int,
end_day: int,
end_hour: int,
buffer_m: float = 128.0,
typical_building_height_m: float = 25.0,
max_building_height_m: Optional[float] = None,
) -> SunContextResult

Estimate whether a tile geometry-context buffer is sufficient.

Parameters:

NameTypeDescriptionDefault
latfloatPolygon centroid in degrees. Latitude drives sun-angle math; longitude drives the clock-hour to solar-hour correction (solar_hour = clock_hour + lon/15 - timezone_offset_h).required
lonfloatPolygon centroid in degrees. Latitude drives sun-angle math; longitude drives the clock-hour to solar-hour correction (solar_hour = clock_hour + lon/15 - timezone_offset_h).required
timezone_offset_hOptional[float]Offset of the locale's clock from UTC, in hours. None (the default) approximates it as round(lon / 15), which matches meridian-aligned time zones and is a fine first-order correction for the locales that don't.None
start_monthintTimePeriod cascade-filter bounds. The function samples the (month, day, hour) grid that the API filter would itself process. Year-wrap windows (e.g. start_month=11, end_month=2) are handled.required
start_dayintTimePeriod cascade-filter bounds. The function samples the (month, day, hour) grid that the API filter would itself process. Year-wrap windows (e.g. start_month=11, end_month=2) are handled.required
start_hourintTimePeriod cascade-filter bounds. The function samples the (month, day, hour) grid that the API filter would itself process. Year-wrap windows (e.g. start_month=11, end_month=2) are handled.required
end_monthintTimePeriod cascade-filter bounds. The function samples the (month, day, hour) grid that the API filter would itself process. Year-wrap windows (e.g. start_month=11, end_month=2) are handled.required
end_dayintTimePeriod cascade-filter bounds. The function samples the (month, day, hour) grid that the API filter would itself process. Year-wrap windows (e.g. start_month=11, end_month=2) are handled.required
end_hourintTimePeriod cascade-filter bounds. The function samples the (month, day, hour) grid that the API filter would itself process. Year-wrap windows (e.g. start_month=11, end_month=2) are handled.required
buffer_mfloatEffective per-cell context buffer. Pass 128 for the current SOLAR_TILING_CONFIG default, 205 for a wind-style 50% overlap (inner-256 crop), or whatever a custom configuration produces.128.0
typical_building_height_mfloatReference building height for the headline severity. Default 25 is reasonable for European mid-rise; raise for high-rise contexts (50–100+ m).25.0
max_building_height_mOptional[float]Optional worst-case height. When supplied, drives the severity scoring (severity = breakeven / max(typical, max)) so that a single tall outlier does not slip past as ok.None

Returns:

TypeDescription
SunContextResultTypedDict with severity (one of SEVERITY_LEVELS), a human-readable message, and supporting numerical fields. The function never raises on bad input; it returns severity="info" with a diagnostic message instead.

required_buffer_m

Python
required_buffer_m(building_height_m: float, sun_elevation_deg: float) -> float

Geometric buffer needed for a single building's full shadow to fit.

Returns +inf for non-positive sun elevations.

run_preflight_safely

Python
run_preflight_safely(
payloads,
polygon_centroid_lat: Optional[float] = None,
polygon_centroid_lon: Optional[float] = None,
mode: str = "log",
logger=None,
buffer_m: float = 128.0,
) -> None

Defensive wrapper around estimate_sun_context_loss for use inside the SDK's area-orchestration entry points.

The whole body is wrapped so that no preflight failure ever propagates — internal exceptions emit a debug log and return. Only an explicit mode="raise" plus a real warning/critical verdict will raise PreflightWarning.

Parameters:

NameTypeDescriptionDefault
payloadsSingle payload or iterable of payloads. Anything that is not a solar/thermal payload (no time_period / no latitude) is silently skipped.required
polygon_centroid_latOptional[float]Fallback location if a payload itself lacks latitude/longitude.None
modestr"off" — function is a no-op (still won't raise). "log" — emit logger.warning for warning/critical results. "raise" — additionally raise PreflightWarning for warning/critical results. Any other value is treated as "log".'log'
loggerOptional logging.Logger used for the warning. Falls back to the module logger when None.None
buffer_mfloatEffective per-cell context buffer for the active tiling config. Default 128 matches SOLAR_TILING_CONFIG's margin.128.0

solar_elevation_deg

Python
solar_elevation_deg(lat_deg: float, doy: int, solar_hour: float) -> float

Return the approximate solar elevation in degrees.

Uses a sinusoidal declination model (δ ≈ 23.45° · sin(360°/365 · (n − 81))) and the standard altitude formula. Equation-of-time and atmospheric refraction are intentionally not modelled — accuracy is well within the ~5° tolerance required for a pre-flight gate.

Returns nan for a non-finite solar_hour (a literal +inf or -inf) rather than raising.