---
title: Analyses
source: https://infrared.city/docs/sdk/1.0/python/analyses/
---

# Analyses

Analysis service, job management, and payload types.

## AnalysesUnion  `module-attribute`

```python
AnalysesUnion = Union[
DaylightFactorModelRequest,
EnergyBalanceModelRequest,
WindModelRequest,
SolarModelRequest,
SvfModelRequest,
SolarRadiationModelRequest,
UtciModelRequest,
TcsModelRequest,
PwcModelRequest,
]
```

Union type covering all analysis request payloads.

This is the canonical definition; `analyses.service` and `analyses.jobs` re-export this same alias.

## AnalysisServiceClient

Bases: `_PartsMixin`

Client that submits single analysis jobs through a jobs client.

It sends nothing itself: every call is delegated to `jobs_service`.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `api_key` | `str` | The Infrared API key. | *required* |
| `logger` | `Logger` | The logger the client writes to. | *required* |
| `base_url` | `str` | The base URL of the Infrared API. | *required* |
| `execution_config` | `[ExecutionConfig](#infrared_sdk.analyses.ExecutionConfig)` | How jobs are executed. The only mode is `ExecutionConfig.exec_async`, which is the default. | `[exec_async](#infrared_sdk.analyses.ExecutionConfig.exec_async)` |
| `jobs_service` | `[JobsServiceClient](#infrared_sdk.analyses.JobsServiceClient)` | The client that submits the jobs. `execute` raises `ValueError` when it is missing. | `None` |
| `telemetry` | `Telemetry` | The application and SDK identity. `None` resolves it from the environment and the defaults. | `None` |

### execute

```python
execute(
*,
payload: AnalysesUnion,
webhook_url: Optional[str] = None,
webhook_events: Optional[List[str]] = None,
transport: Optional[str] = None,
_planned: bool = False,
) -> Job
```

Submit ONE job and return its handle; never splits.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `payload` | `[AnalysesUnion](#infrared_sdk.analyses.AnalysesUnion)` | The analysis request payload. | *required* |
| `webhook_url` | `str` | A URL the service notifies about the job. | `None` |
| `webhook_events` | `list of str` | The events to subscribe to, for example `["job.succeeded", "job.failed"]`. If omitted the service default applies. | `None` |
| `transport` | `(json, binary)` | The transport for the request. `None` (the default) lets the SDK choose for the analysis type. | `"json"` |

Returns:

| Type | Description |
| --- | --- |
| `[Job](#infrared_sdk.analyses.Job)` | The handle of the submitted job. |

Raises:

| Type | Description |
| --- | --- |
| `ValueError` | If `execution_config` is invalid, no `jobs_service` was provided, or `transport` is not `"json"` or `"binary"`. |
| `JobSubmitError` | If the submission request fails. |

Notes

For a daylight-factor request that the SDK plans into more than one part, a warning names the part count: `run_and_wait` splits it automatically and runs faster. The request is sent unchanged.

## ExecutionConfig

Bases: `StrEnum`

How an analysis job is executed.

### exec_async  `class-attribute` `instance-attribute`

```python
exec_async = 'async'
```

Submit the job and poll for its result.

## Job  `dataclass`

Immutable snapshot of a job returned by the API.

### from_response  `classmethod`

```python
from_response(data: dict) -> 'Job'
```

Build a Job from an API response dict (camelCase keys).

Handles both `status` (submit response) and `jobStatus` (poll response) field names, and normalises the `"Succeded"` typo to `JobStatus.succeeded`.

### to_dict

```python
to_dict() -> dict
```

Return camelCase dict, excluding None values.

## JobsServiceClient

Bases: `_JobsSubmitMixin`, `_JobsTransportMixin`, `_JobsPollMixin`, `ScrubbedSessionState`

Client for async job submission, polling, and result download.

Manages its own `requests.Session` and implements the context-manager protocol for clean session teardown.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `api_key` | `str` | The Infrared API key. | *required* |
| `logger` | `Logger` | The logger the client writes to. | *required* |
| `base_url` | `str` | The base URL of the Infrared API. | *required* |
| `transport` | `('json', 'binary')` | The transport for submissions. `None` (the default) lets the SDK choose for each analysis type. | `"json"` |
| `backoff_cap` | `float` | The longest wait, in seconds, between status polls while the service is healthy. Must be greater than 0. | `None` |
| `gateway_base_url` | `str` | The base URL of the gateway used for large uploads. Derived from `base_url` when omitted. | `None` |
| `telemetry` | `Telemetry` | The application and SDK identity sent with every request. `None` resolves it from the environment and the defaults. | `None` |

Raises:

| Type | Description |
| --- | --- |
| `ValueError` | If `transport` is not `"json"` or `"binary"`, or `backoff_cap` is not greater than 0. |

### close

```python
close() -> None
```

Close both the API session and the S3 session.

## AnalysesName

Bases: `StrEnum`

The analysis models, as the API spells them.

### wind_speed  `class-attribute` `instance-attribute`

```python
wind_speed = 'wind-speed'
```

Wind speed field for one wind speed and direction.

### pedestrian_wind_comfort  `class-attribute` `instance-attribute`

```python
pedestrian_wind_comfort = 'pedestrian-wind-comfort'
```

Pedestrian wind comfort against a chosen criterion (`PwcCriteria`).

### daylight_availability  `class-attribute` `instance-attribute`

```python
daylight_availability = 'daylight-availability'
```

Daylight availability over a time window.

### direct_sun_hours  `class-attribute` `instance-attribute`

```python
direct_sun_hours = 'direct-sun-hours'
```

Hours of direct sun over a time window.

### sky_view_factors  `class-attribute` `instance-attribute`

```python
sky_view_factors = 'sky-view-factors'
```

Sky view factor.

### solar_radiation  `class-attribute` `instance-attribute`

```python
solar_radiation = 'solar-radiation'
```

Solar radiation over a time window.

### thermal_comfort_index  `class-attribute` `instance-attribute`

```python
thermal_comfort_index = 'thermal-comfort-index'
```

Thermal comfort index (UTCI) over a time window.

### thermal_comfort_statistics  `class-attribute` `instance-attribute`

```python
thermal_comfort_statistics = 'thermal-comfort-statistics'
```

Thermal comfort statistics (see `TcsSubtype`) over a time window.

### daylight_factor  `class-attribute` `instance-attribute`

```python
daylight_factor = 'daylight-factor'
```

Interior daylight factor under a CIE overcast sky.

Not an area model: it takes explicit room geometry and cannot be used with the area runners.

### energy_balance  `class-attribute` `instance-attribute`

```python
energy_balance = 'energy-balance'
```

Monthly heating and cooling energy need per zone.

Not an area model: it takes explicit zones and cannot be used with the area runners.

## TerrainAlignment

Bases: `StrEnum`

How supplied buildings and trees relate to terrain.

### as_is  `class-attribute` `instance-attribute`

```python
as_is = 'as-is'
```

Use the supplied coordinates exactly as given.

### auto_align  `class-attribute` `instance-attribute`

```python
auto_align = 'auto-align'
```

Seat the supplied buildings and trees on the terrain automatically.

### assume_aligned  `class-attribute` `instance-attribute`

```python
assume_aligned = 'assume-aligned'
```

Treat the supplied scene as already aligned to the terrain.

## PwcCriteria

Bases: `StrEnum`

Pedestrian wind comfort criteria, as the API spells them.

### vdi_3787  `class-attribute` `instance-attribute`

```python
vdi_3787 = 'vdi-3787'
```

VDI 3787 criterion.

### vdi_387  `class-attribute` `instance-attribute`

```python
vdi_387 = 'vdi-3787'
```

Alias of `vdi_3787`, kept for backward compatibility.

### lawson_1970  `class-attribute` `instance-attribute`

```python
lawson_1970 = 'lawson-1970'
```

Lawson (1970) criterion.

### lawson_2001  `class-attribute` `instance-attribute`

```python
lawson_2001 = 'lawson-2001'
```

Lawson (2001) criterion.

### lawson_lddc  `class-attribute` `instance-attribute`

```python
lawson_lddc = 'lawson-lddc'
```

Lawson LDDC criterion.

### davenport  `class-attribute` `instance-attribute`

```python
davenport = 'davenport'
```

Davenport criterion.

### nen_8100_comfort  `class-attribute` `instance-attribute`

```python
nen_8100_comfort = 'nen-8100-comfort'
```

NEN 8100 comfort criterion.

### nen_8100_safety  `class-attribute` `instance-attribute`

```python
nen_8100_safety = 'nen-8100-safety'
```

NEN 8100 safety criterion.

## PhysicsTier

Bases: `StrEnum`

The sky and mean radiant temperature formulation a thermal run uses.

Set it with the `physics` field of a thermal-comfort-index or thermal-comfort-statistics request. Only the values below are accepted: an unknown value is refused when the request is built, so a typo cannot silently select a different formulation and still be billed.

When `physics` is left unset, the model's own default applies, which is `advanced-moist` for both models.

Warnings

`v1` is deprecated. Use the default tier (leave `physics` unset) or pick `detail`, `advanced` or `advanced-moist`. A later release will remove `v1`.

### v1  `class-attribute` `instance-attribute`

```python
v1 = 'v1'
```

Deprecated. Leave `physics` unset, or use another tier.

### detail  `class-attribute` `instance-attribute`

```python
detail = 'detail'
```

The `detail` tier.

### advanced  `class-attribute` `instance-attribute`

```python
advanced = 'advanced'
```

The `advanced` tier.

### advanced_moist  `class-attribute` `instance-attribute`

```python
advanced_moist = 'advanced-moist'
```

The `advanced-moist` tier, the model default when `physics` is unset.

## PwcModelRequest

Bases: `PwcModelBaseReq`

Pedestrian wind comfort request: hourly wind observations and a criterion.

Creating the request raises a validation error (a `ValueError`) when `wind_speed` and `wind_direction` differ in length, or when fewer than two speeds are above zero (a Weibull fit needs at least two).

### wind_speed  `instance-attribute`

```python
wind_speed: DataList
```

Hourly wind speeds, paired by position with `wind_direction`.

### wind_direction  `instance-attribute`

```python
wind_direction: DataList
```

Hourly wind directions, paired by position with `wind_speed`.

## SolarModelRequest

Bases: `BaseAnalysisPayload[SolarAnalysisName]`, `SurfaceSensorFieldsMixin`, `TerrainFieldsMixin`, `[Location](../models/#infrared_sdk.models.Location)`

Direct sun hours or daylight availability request.

The analysis name selects the model (`AnalysesName.direct_sun_hours` or `AnalysesName.daylight_availability`). Supports facade, roof and own sensor analysis (`SurfaceSensorFieldsMixin`) and terrain (`TerrainFieldsMixin`).

### time_period  `instance-attribute`

```python
time_period: TimePeriod
```

The analysis window: a date span with a daily hour range.

### accuracy  `class-attribute` `instance-attribute`

```python
accuracy: Optional[Literal['standard', 'precision']] = None
```

Ray-tracing accuracy, `"standard"` or `"precision"`.

Unset means `"standard"`.

### fast  `class-attribute` `instance-attribute`

```python
fast: Optional[bool] = None
```

Fast mode for a long time window.

Optional; unset sends nothing. The direct sun hours and daylight availability models do not use it yet, so setting it currently has no effect on the result.

## SolarRadiationModelRequest

Bases: `BaseAnalysisPayload[SrAnalysisName]`, `SurfaceSensorFieldsMixin`, `TerrainFieldsMixin`, `[Location](../models/#infrared_sdk.models.Location)`

Solar radiation request, with the hourly radiation series it needs.

Build one from a weather file with `from_weatherfile_payload`.

### time_period  `instance-attribute`

```python
time_period: TimePeriod
```

The analysis window: a date span with a daily hour range.

### diffuse_horizontal_radiation  `instance-attribute`

```python
diffuse_horizontal_radiation: DataList
```

Hourly diffuse horizontal radiation for the analysis window.

### direct_normal_radiation  `instance-attribute`

```python
direct_normal_radiation: DataList
```

Hourly direct normal radiation for the analysis window.

### from_weatherfile_payload  `classmethod`

```python
from_weatherfile_payload(
payload: BaseAnalysisPayload,
location: Location,
time_period: TimePeriod,
weather_data: Any,
)
```

Build a solar radiation request from weather data.

The surface-sensor fields (`analysis_surfaces`, `surface_grid_size`, `emit_cell_tris` and the rest of `SurfaceSensorFieldsMixin`) and the terrain fields (`TerrainFieldsMixin`) set on `payload` are carried over to the new request.

There is no `solar_model` selector here. This request cannot ask for the interior-irradiance model, so checking a file against that model's required columns would be misleading. To ask which columns a model needs, call `model_inputs` on the weather document.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `payload` | `BaseAnalysisPayload` | The request to extend: its geometry, vegetation, ground materials, surface-sensor and terrain fields are reused. | *required* |
| `location` | `[Location](../models/#infrared_sdk.models.Location)` | Latitude and longitude of the site. | *required* |
| `time_period` | `[TimePeriod](../models/#infrared_sdk.models.TimePeriod)` | The analysis window. | *required* |
| `weather_data` | `WeatherDocument or list of WeatherDataPoint` | A parsed EPW document (see `parse_epw`) or the already-filtered records of the public weather catalog. | *required* |

Returns:

| Type | Description |
| --- | --- |
| `[SolarRadiationModelRequest](#infrared_sdk.analyses.SolarRadiationModelRequest)` | The request, with the radiation series filled in. |

Raises:

| Type | Description |
| --- | --- |
| `ValueError` | If a required weather column has a gap inside the window, or the weather document cannot supply what the model needs. |

## SvfModelRequest

Bases: `BaseAnalysisPayload[SvfAnalysisName]`, `SurfaceSensorFieldsMixin`, `TerrainFieldsMixin`

Sky view factor request.

### latitude  `class-attribute` `instance-attribute`

```python
latitude: Optional[Latitude] = None
```

Latitude of the site in degrees; the area runners fill it in per tile.

### longitude  `class-attribute` `instance-attribute`

```python
longitude: Optional[Longitude] = None
```

Longitude of the site in degrees; the area runners fill it in per tile.

## TcsModelBaseRequest

Bases: `BaseAnalysisPayload[ThermalStatisticsAnalysisName]`, `ThermalControlFieldsMixin`, `Generic[TcsSName]`

Thermal comfort statistics request without weather: geometry and controls.

Pass it to `TcsModelRequest.from_weatherfile_payload` to add the weather series and time window.

### subtype  `instance-attribute`

```python
subtype: TcsSName
```

Which statistic to compute (see `TcsSubtype`).

## UtciModelRequest

Bases: `UtciModelBaseRequest`, `TerrainFieldsMixin`, `[Location](../models/#infrared_sdk.models.Location)`, `ThermalModelRequestWeatherDataMixin`

Thermal comfort index (UTCI) request with its weather series.

Build one from a weather file with `from_weatherfile_payload`.

### time_period  `instance-attribute`

```python
time_period: TimePeriod
```

The analysis window: a date span with a daily hour range.

### fast  `class-attribute` `instance-attribute`

```python
fast: Optional[bool] = None
```

Fast mode for a long time window.

Unset uses the server default, which is on for windows longer than one week. Fast mode uses a fixed grid of sun directions; at least 99 % of cells are within 0.5 degC of the exact run. Set `False` for the exact computation.

### from_weatherfile_payload  `classmethod`

```python
from_weatherfile_payload(
payload: UtciModelBaseRequest,
location: Location,
time_period: TimePeriod,
weather_data: Any,
)
```

Build a thermal comfort index request from weather data.

The thermal controls and the terrain fields (`ground_geometry`, `terrain_alignment`) set on `payload` are carried over to the new request. With a weather document, the seven required columns are checked on the rows inside the window, so a gap in the window raises here and not after the job is charged.

Parameters:

| Name | Type | Description | Default |
| --- | --- | --- | --- |
| `payload` | `UtciModelBaseRequest` | The request to extend: its geometry, vegetation, ground materials, thermal controls and terrain fields are reused. | *required* |
| `location` | `[Location](../models/#infrared_sdk.models.Location)` | Latitude and longitude of the site. | *required* |
| `time_period` | `[TimePeriod](../models/#infrared_sdk.models.TimePeriod)` | The analysis window. | *required* |
| `weather_data` | `WeatherDocument or list of WeatherDataPoint` | A parsed EPW document (see `parse_epw`) or the already-filtered records of the public weather catalog. | *required* |

Returns:

| Type | Description |
| --- | --- |
| `[UtciModelRequest](#infrared_sdk.analyses.UtciModelRequest)` | The request, with the weather series filled in. |

Raises:

| Type | Description |
| --- | --- |
| `ValueError` | If a required weather column has a gap inside the window, or the weather document cannot supply what the model needs. |

## WindModelRequest

Bases: `BaseAnalysisPayload[WindAnalysisName]`, `GradeFieldsMixin`

Single-direction wind request.

The two fields are deliberately typed differently, because the model treats them differently:

- `wind_speed` is continuous. The model applies the speed as a linear scalar after it has computed the wind field from the geometry, so any value in the range is exactly as valid as any other. Fractional speeds are the normal case: a prevailing wind derived from a weather file is a mean (for example `3.9`). Zero is the calm-wind baseline, not an error.
- `wind_direction` is whole degrees. The model truncates it to an integer bearing to rotate the scene, so a fractional value would be silently shifted (22.5 would simulate 22). It is rejected instead, at construction.

Neither field has an upper bound. Bearings outside 0 to 360, such as `450` and `-90`, are accepted and wrap to the equivalent bearing.

Warnings

Do not round `wind_speed` to a whole number: at 3.9 m/s, truncating to 3 shifts every cell by -23 % and rounding to 4 by +2.6 %.

### wind_speed  `instance-attribute`

```python
wind_speed: Annotated[float, Field(ge=0, allow_inf_nan=False)]
```

Wind speed in m/s: a finite number, zero or more. Fractions are allowed.

### wind_direction  `instance-attribute`

```python
wind_direction: int
```

Wind direction in whole degrees; fractional values are rejected.

### latitude  `class-attribute` `instance-attribute`

```python
latitude: Optional[Latitude] = None
```

Latitude of the site in degrees; the area runners fill it in per tile.

### longitude  `class-attribute` `instance-attribute`

```python
longitude: Optional[Longitude] = None
```

Longitude of the site in degrees; the area runners fill it in per tile.
