{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## Edit the threedimodel DEM for a simulation\n",
    "\n",
    "In this notebook we will go through the steps of editing the DEM file of your threedimodel for a simulation.\n",
    "\n",
    "Let's first import all required modules for the notebook and provide our credentials to connect to the\n",
    "threedi-api."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "from datetime import datetime\n",
    "from getpass import getpass\n",
    "from threedi_api_client.openapi import ApiException\n",
    "from threedi_api_client.openapi.models import RasterEdit\n",
    "from threedi_api_client.api import ThreediApi\n",
    "from threedi_api_client.versions import V3Api\n",
    "\n",
    "API_HOST = \"https://api.3di.live\"\n",
    "PERSONAL_API_KEY = getpass(\"Personal API token\")  # https://management.3di.live/personal_api_keys\n",
    "\n",
    "\n",
    "config = {\n",
    "    \"THREEDI_API_HOST\": API_HOST,\n",
    "    \"THREEDI_API_PERSONAL_API_TOKEN\": PERSONAL_API_KEY\n",
    "}\n",
    "\n",
    "api_client: V3Api = ThreediApi(config=config)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Check if we can connect to the threedi-api with the provided credentials:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    user = api_client.auth_profile_list()\n",
    "except ApiException as e:\n",
    "    print(\"Oops, something went wrong. Maybe you made a typo?\")\n",
    "else:\n",
    "    print(f\"Successfully logged in as {user.username}!\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "To run a simulation we'll need a threedimodel. Let's see which threedimodels are\n",
    "available:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "models = api_client.threedimodels_list(limit=5)  # limit to the first 5 results\n",
    "for model in models.results:\n",
    "    print(f\"{model.name}\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "If we already know the name of a specific model, we can also look it up with the following api call:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "my_model = api_client.threedimodels_list(name__icontains='v2_bergermeer')\n",
    "print(my_model)\n",
    "\n",
    "my_model = my_model.results[0]"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Now that we have a threedimodel we are almost ready to create the simulation. But first we'll need\n",
    "to get an organisation under which name we will run the simulation.\n",
    "\n",
    "Let's see which organisations are available:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "organisations = api_client.organisations_list()\n",
    "for organisation in organisations.results:\n",
    "    print(f\"{organisation.name}: {organisation.unique_id}\")\n",
    "\n",
    "# Here I use the following organisation, you should select from the list below\n",
    "organisation_uuid = \"a1993f6e13564e9687ae03a3604463f9\"\n",
    "threedimodel = api_client.threedimodels_list(name__icontains='v2_bergermeer').results[0]\n",
    "\n",
    "# Retrieve first simulation template\n",
    "simulation_templates = api_client.simulation_templates_list(simulation__threedimodel__id=threedimodel.id)\n",
    "assert simulation_templates.count > 0, f\"No simulation templates found for threedimodel {threedimodel.name}\"\n",
    "simulation_template_id = simulation_templates.results[0].id"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "# Now we got all the pieces to create a simulation\n",
    "my_simulation = api_client.simulations_from_template(\n",
    "    data={\n",
    "        \"template\": simulation_template_id,\n",
    "        \"name\": \"my first simulation\",\n",
    "        \"organisation\": organisation_uuid,\n",
    "        \"start_datetime\": datetime.now(),\n",
    "        \"duration\": 3600  # in seconds, so we simulate for 1 hour\n",
    "    }\n",
    ")\n",
    "\n",
    "status = api_client.simulations_status_list(my_simulation.id)\n",
    "print(status)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will now initialize the simulation and add our DEM edits.\n",
    "First we need to find our model's DEM. The model has a list of rasters:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_model_rasters = api_client.threedimodels_rasters_list(my_model.id)\n",
    "my_model_rasters.results"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "From this list, we need the id of the DEM:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for raster in my_model_rasters.results:\n",
    "    if raster.type == 'dem_file':\n",
    "        raster_id = raster.id\n",
    "        break\n",
    "print(f'id of dem raster: {raster_id}')"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we have what we need to make the raster edit API call:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = {\n",
    "  \"offset\": 0, # time in seconds since start of simulation\n",
    "  \"value\": 2.5, # new height in mMSL\n",
    "  \"raster\": raster_id,\n",
    "  \"polygon\": {\n",
    "    \"type\": \"Polygon\",\n",
    "    \"coordinates\": [\n",
    "      [\n",
    "        [\n",
    "          4.699366986751557,\n",
    "          52.64294137346387\n",
    "        ],\n",
    "        [\n",
    "          4.699687510728837,\n",
    "          52.64336289692115\n",
    "        ],\n",
    "        [\n",
    "          4.700147509574891,\n",
    "          52.642926725857535\n",
    "        ],\n",
    "        [\n",
    "          4.699698239564897,\n",
    "          52.64304716158594\n",
    "        ],\n",
    "        [\n",
    "          4.699366986751557,\n",
    "          52.64294137346387\n",
    "        ]\n",
    "      ]\n",
    "    ]\n",
    "  }\n",
    "}\n",
    "\n",
    "raster_edit = RasterEdit(**data)\n",
    "\n",
    "\n",
    "# POST the edit to the API\n",
    "raster_edit_result = api_client.simulations_events_raster_edits_create(my_simulation.id, raster_edit)\n",
    "raster_edit_result"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To make it a bit easier, we can also use a polygon shapefile as input for the raster edits. In this case, a shapefile with the elevation and (time) offset stored in the attribute table:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import ogr\n",
    "import osr\n",
    "\n",
    "polygons_fn = \"dem_edits.shp\"\n",
    "datasource = ogr.Open(polygons_fn)\n",
    "layer = datasource.GetLayer()\n",
    "\n",
    "# Create a CoordinateTransformation to WGS84, as required by the API\n",
    "source_srs = layer.GetSpatialRef()\n",
    "target_srs = osr.SpatialReference()\n",
    "target_srs.ImportFromEPSG(4326)\n",
    "transform = osr.CoordinateTransformation(source_srs, target_srs)\n",
    "\n",
    "for feature in layer:\n",
    "    geom = feature.GetGeometryRef()\n",
    "    geom.Transform(transform)\n",
    "    wkt = geom.ExportToWkt()\n",
    "    data = {\n",
    "      \"offset\": feature['offset'], # time in seconds since start of simulation\n",
    "      \"value\": feature['elevation'], # new height in mMSL\n",
    "      \"raster\": raster_id,\n",
    "      \"polygon\": wkt\n",
    "    }\n",
    "\n",
    "    raster_edit = RasterEdit(**data)\n",
    "\n",
    "\n",
    "    # POST the edit to the API\n",
    "    raster_edit_result = api_client.simulations_events_raster_edits_create(my_simulation.id, raster_edit)\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "To run this simulation we have to tell it to start:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "api_client.simulations_actions_create(my_simulation.id, data={\"name\": \"start\", \"max_rate\": 10})"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Eventually the simulation will finish. You can periodically check its progress by calling\n",
    "for the status again:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "api_client.simulations_status_list(my_simulation.id)\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Eventually you should see something like this::\n",
    "\n",
    "    {\n",
    "        'created': datetime.datetime(2020, 7, 27, 14, 7, 6, 654905, tzinfo=tzutc()),\n",
    "        'id': 15866,\n",
    "        'name': 'finished',\n",
    "        'paused': False,\n",
    "        'time': 3600.0\n",
    "     }\n",
    "\n",
    "Congratulations, you just made your first simulation with a DEM edit via the threedi-api-client!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
