Skip to content
View as Markdown llms.txt

Python SDK

API reference for infrared_sdk, generated from the docstrings in the SDK source. Start with the overview below, then the module pages in the sidebar.

A typical run

A chain of seven steps from left to right: client, model (yours or public data), weather, request, preview, run and values. Only the run is billed.

This is a complete run with your own model: one tower and a thermal comfort (UTCI) analysis. Each comment is one step of the diagram. polygon is a GeoJSON polygon in longitude and latitude. coordinates and indices are your mesh, in metres, in the local frame of the polygon. See Your model and Coordinates.

import os

from infrared_sdk import InfraredClient
from infrared_sdk.analyses.types import (
    AnalysesName, UtciModelBaseRequest, UtciModelRequest,
)
from infrared_sdk.models import Location, TimePeriod

# 1. Client. The key comes from the argument or from INFRARED_API_KEY.
client = InfraredClient(api_key=os.environ["INFRARED_API_KEY"])

# 2. Your model. One mesh for each building, in metres.
buildings = {"tower": {"coordinates": coordinates, "indices": indices}}

# 3. Weather. Find the nearest public station, then keep the hours you need.
period = TimePeriod(start_month=7, start_day=15, start_hour=12,
                    end_month=7, end_day=15, end_hour=16)
stations = client.weather.get_weather_file_from_location(lat=48.2085, lon=16.3725)
rows = client.weather.filter_weather_data(
    identifier=stations[0]["uuid"], time_period=period)

# 4. Request. There is one request class for each analysis.
payload = UtciModelRequest.from_weatherfile_payload(
    payload=UtciModelBaseRequest(analysis_type=AnalysesName.thermal_comfort_index),
    location=Location(latitude=48.2085, longitude=16.3725),
    time_period=period,
    weather_data=rows,
)

# 5. Preview. This sends no job. would_bill_jobs is the number of billed jobs.
preview = client.preview_area(polygon, payload=payload, buildings=buildings)
print(preview.tile_count, preview.would_bill_jobs)

# 6. Run. One call plans, uploads, submits, waits and merges.
result = client.run_area_and_wait(payload, polygon, buildings=buildings)

# 7. Values. A float64 grid in degrees C. NaN means no value.
values = result.physical_grid()
client.close()

To use your own weather file, give weather_data=parse_epw("vienna.epw"). An analysis that needs no weather takes the request class alone, for example SvfModelRequest(analysis_type=AnalysesName.sky_view_factors). See Weather and time period, The ten analyses, Cost and retry and How a run works.

Variant: no data yet

Read public buildings, trees and ground materials for the polygon. Give the objects to the run as they are, not only their inner maps: then the run can check the frame and the read margin. Buildings and ground materials need pip install "infrared-sdk[geodata]". See Public context.

buildings = client.buildings.get_area(polygon)
trees = client.vegetation.get_area(polygon)
ground = client.ground_materials.get_area(polygon)
result = client.run_area_and_wait(payload, polygon, buildings=buildings,
                                  vegetation=trees, ground_materials=ground)

Variant: facades instead of ground

Set analysis_surfaces to "facades", "roofs" or "all". The result gives one value for each sensor cell on your buildings, not a ground grid. Give payload= to the preview, or the facade job count is too low. See Facade and roof runs.

from infrared_sdk import SvfModelRequest

payload = SvfModelRequest(analysis_type=AnalysesName.sky_view_factors,
                          analysis_surfaces="facades", surface_grid_size=3.0)
preview = client.preview_area(polygon, payload=payload, buildings=buildings)
result = client.run_area_and_wait(payload, polygon, buildings=buildings)
values = result.columns.physical_values()   # float64, one value for each cell
buffers = result.columns.render_buffers()   # flat arrays to draw the cells

Variant: submit now, merge later

run_area submits the jobs and returns an AreaSchedule at once. Merge when the jobs are complete. check_area_state asks for up to 50 jobs in one request. Do not ask for each job in a loop. Give the same known dict each time: then the SDK does not ask again for a job that is finished. A list of requests gives one schedule for each request.

import time

schedule = client.run_area(payload, polygon, buildings=buildings)
known = {}
while not client.check_area_state(schedule, known=known).is_complete:
    time.sleep(10)
result = client.merge_area_jobs(schedule)

Save, reload and free

Save the layout of a facade run one time for each geometry, and the values of each run: layout.to_bytes() and result.columns.to_bytes(). Reload with FacadeLayout.from_bytes and SurfaceColumns.from_bytes, then attach_values. Call client.forget_schedule(schedule) for a schedule that you will not merge, and client.close() when you finish. See Save, reload and free.

Which module does what

Page Role Main calls
Client The entry point and the area runs InfraredClient, preview_area, run_area_and_wait, run_area, check_area_state, merge_area_jobs, forget_schedule
Analyses Requests, results and job errors SvfModelRequest, UtciModelRequest, SurfaceColumns, InfraredJobError
Buildings, Vegetation, Ground materials Public context for an area client.buildings.get_area, client.vegetation.get_area, client.ground_materials.get_area
Layers (weather) The weather catalog and EPW files get_weather_file_from_location, filter_weather_data, parse_epw
Tiling Tiles, schedules, previews, area results AreaPreview, AreaSchedule, AreaResult, physical_grid
Facade layout The outline of facade and roof results FacadeLayout.to_bytes, FacadeLayout.from_bytes, attach_values
Legend Colour-scale ranges legend_range, shared_legend_range
Webhooks Calls to your server when a job ends client.webhooks

Errors you meet

Catch these by name. The area errors and the job errors are different classes.

  • AreaRunError: a merge cannot give a complete grid, because a tile did not contribute.
  • AreaTimeoutError: the run passed area_timeout. It holds the area_state.
  • JobFailedError: one job failed on the server. It is a kind of InfraredJobError.
  • ReadMarginError: a public layer was read with a margin that is too narrow for the analysis.
  • EpwParseError: your EPW file is not valid, for example it is not hourly.

See also Cost and retry for retry keys and the 402 answer when you have no credits.

Infrared SDK - Python client for the Infrared City API.