Examples

First, get an instance of the ThreediApi:

from threedi_api_client import ThreediApi
env_file = "<path>/.env"
api = ThreediApi(env_file)

Now you can easily make use of the api models generated by the openapi client. Let us create a simulation. We will use a Simulation model instance to pass data to the API. Some fields are optional but we do need to specify:

  • the unique organisation ID we want to run the simulation for

  • the model schema to use for the simulation by referring to the id of the threedimodel resource

  • datetime (in ISO 8601 (UTC) format) for the simulation start

  • either a end datetime (also in ISO 8601 (UTC) format) or the duration parameter in seconds

If you do not know the unique ID for your organisation you can make use of the API to request it.

api.organisations_list(name__istartswith="nelen")
{'count': 2,
'next': None,
'previous': None,
'results': [{'name': 'Nelen & Schuurmans',
      'unique_id': 'b8f91de705774fe8a4e7cb2d9413bf5c',
      'url': 'https://api.3di.live/v3.0/organisations/61f5a464c35044c19bc7d4b42d7f58cb/'},
     {'name': 'Nelen & Schuurmans alleen werknemers',
      'unique_id': 'e82c74c4fb5846b3ae990c0cc69130c6',
      'url': 'https://api.3di.live/v3.0/organisations/cde64bc165644be9af023fc4fa18d098/'}]}

Now we can create the Simulation model instance.

from threedi_api_client.openapi import Simulation

# start date will be a datetime object
from datetime import datetime

my_extreme_event_simulation = Simulation(
        name="my extreme event",   # (optional)
        threedimodel=1,            # The model schema to use for the simulation by referring to the id of the threedimodel resource
        organisation='b8f91de705774fe8a4e7cb2d9413bf5c',
        start_datetime=datetime.utcnow(),  # accepts datetime instance
        duration=7200              # in secs ==> 2 hours
)

The simulations_create method allows you to create a new Simulation resource.

api.simulations_create(my_extreme_event_simulation)
{'created': 'now',
'duration': 7200,
'duration_humanized': '2 hours, 0 minutes, 0 seconds',
'end_datetime': '2019-11-04T16:19:46Z',
'id': 631,
'name': 'my extreme event',
'organisation': 'b8f91de705774fe8a4e7cb2d9413bf5c',
'organisation_name': 'Nelen & Schuurmans',
'slug': 'my-extreme-event-378f55a5-06df-4021-8fb6-65bbb70519dc',
'start_datetime': '2019-11-04T14:19:46Z',
'threedimodel': 'https://api.3di.live/v3.0/threedimodels/1/',
'threedimodel_id': '1',
'url': 'https://api.3di.live/v3.0/simulations/631/',
'user': 'lars.claussen',
'uuid': '378f55a5-06df-4021-8fb6-65bbb70519dc'}

Simulations allow for adding an arbitrary number of events to them like

  • rain events

  • sources and sinks

  • initial conditions

  • laterals

  • saved states

  • structure controls

All of them have their own openapi client model. To add a constant rain event to the simulation you would do the following.

from threedi_api_client.openapi import ConstantRain
const_rain = ConstantRain(
    simulation=631,   # the ID we got from our create call above
    offset=60,        # let the rain start after one minute
    duration=5000,    # let the rain last for 5000 secs
    value=0.0006,     # not too extreme after all...;-)
    units="m/s"       # the only unit supported for now
)
api.simulations_events_rain_constant_create(631, const_rain)
{'duration': 5000,
'offset': 60,
'simulation': 'https://api.3di.live/v3.0/simulations/631/',
'units': 'm/s',
'url': 'https://api.3di.live/v3.0/simulations/631/events/rain/constant/17/',
'value': 0.0006}

If you want to see which events are defined on a given simulation

api.simulations_events(631)
{'boundaries': None,
'breach': [],
'filerasterrain': [],
'filerastersourcessinks': [],
'filetimeseriesrain': [],
'filetimeseriessourcessinks': [],
'initial_groundwaterlevel': None,
'initial_onedwaterlevel': None,
'initial_onedwaterlevelpredefined': None,
'initial_savedstate': None,
'initial_twodwaterlevel': None,
'laterals': [],
'lizardrasterrain': [],
'lizardrastersourcessinks': [],
'lizardtimeseriesrain': [],
'lizardtimeseriessourcessinks': [],
'savedstates': [],
'timedstructurecontrol': [],
'timeseriesrain': [{'constant': True,
                'duration': 5000,
                'interpolate': False,
                'offset': 60,
                'simulation': 'https://api.3di.live/v3.0/simulations/631/',
                'units': 'm/s',
                'url': 'https://api.3di.live/v3.0/simulations/631/events/rain/timeseries/17/',
                'values': [[0.0, 0.0006], [5000.0, 0.0]]}],
'timeseriessourcessinks': []}

Advanced usage

See below for an example of uploading a rain raster.

from pathlib import Path
from threedi_api_client.files import upload_file

simulation_pk = 1
filename = 'bergermeer_rasters_from_geotiffs.nc'
local_file_path = Path('./data/bergermeer_rasters_from_geotiffs.nc')

# Create rain raster upload resource in API
# returns a 'file_upload' instance containing a
# put_url property which is the URL to the object
# storage object to be uploaded with an HTTP PUT requests.
file_upload = api.simulations_events_rain_rasters_upload(
    filename, simulation_pk)

# Upload the file
upload_file(file_upload.put_url, local_file_path)

Async client

This project also provides an asynchronous api client. To use the async-client make sure you install the optional dependencies using pip install threedi-api-client[aio] and then import from the aio submodule. The async-client works the same as the synchronous client, except all api calls are coroutines.

For example, to asynchronously request files from the api:

import asyncio

from threedi_api_client.api import ThreediApi
from threedi_api_client.openapi.api.v3_api import V3Api

config = {
    "THREEDI_API_HOST": "https://api.3di.live",
    "THREEDI_API_PERSONAL_API_TOKEN": "your_personal_api_token_here"
}


async def main():
    async with ThreediApi(config=config) as api_client:
        api_client: V3Api
        print(await api_client.files_list())


if __name__ == '__main__':
    asyncio.run(main())