diff --git a/notebooks/quick_starter.ipynb b/notebooks/quick_starter.ipynb new file mode 100644 index 0000000..6dce808 --- /dev/null +++ b/notebooks/quick_starter.ipynb @@ -0,0 +1,1365 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Getting Started with Xanthos" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "In this section, we will introduce\n", + "* How to install and run `Xanthos`\n", + "* How to use `Xanthos` functions" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Install Xanthos" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "* Download and install Python (>= 3.6).\n", + "* From a command prompt or terminal, install the latest `Xanthos` version from Github using\n", + "> `python -m pip install git+https://github.com/JGCRI/xanthos.git`\n", + "* (Optional) Clone `Xanthos` to your local folder if you would like to make modifications to `Xanthos`. From a command prompt, navigate to your preferred location, and clone `Xanthos`.\n", + "> `git clone https://github.com/JGCRI/xanthos.git`" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Download Example Data" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "`Xanthos` provides a function `get_package_data` to retrieve and download example data. The example data provided in this tutorial uses WATCH climate forcing data from 1971 to 2001.\n", + "\n", + "To download, open a python console. Make sure to change the `data_dir` to your preferred location. This could take about 10 minutes." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "pycharm": { + "name": "#%%\n" + }, + "ExecuteTime": { + "end_time": "2024-08-05T20:06:01.820299400Z", + "start_time": "2024-08-05T20:05:58.000237900Z" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\knig694\\AppData\\Local\\miniconda3\\envs\\xanthos\\Lib\\site-packages\\xanthos\\drought\\drought_stats.py:86: SyntaxWarning: invalid escape sequence '\\s'\n", + " \"\"\"Compute Severity, Intensity, and Duration statistics for a matrix of hydrological output.\n" + ] + } + ], + "source": [ + "import xanthos\n", + "\n", + "# the directory that you want to download and extract the example data to\n", + "data_dir = 'C:\\\\xanthos-dev\\\\xanthos-dev\\\\data'\n", + "\n", + "# download and unzip the package data to your local machine\n", + "# xanthos.get_package_data(data_dir)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Set Up Configuration File" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "The configuration file (e.g., `pm_abcd_mrtm.ini`) is located in the `example` folder downloaded from the previous step. Make sure to change the following variables in the configuration file to represent the local path to your example data: `RootDir`, `TempMinFile`, `PrecipitationFile`.\n", + "\n", + "If you are using [Xanthos AWS Server](https://xanthos.msdlive.org/), the function `get_data_dir` will find your relative path to the example data folder." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2024-08-05T20:06:01.856088800Z", + "start_time": "2024-08-05T20:06:01.821297700Z" + } + }, + "outputs": [], + "source": [ + "import os\n", + " \n", + "# get relative path to the data folder\n", + "def get_data_dir():\n", + " return os.path.join(os.path.dirname(os.getcwd()), \"data\")\n", + "\n", + "# root directory\n", + "data_dir = get_data_dir()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's take a look at the example configuration file `pm_abcd_mrtm.ini`." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "pycharm": { + "name": "#%%\n" + }, + "ExecuteTime": { + "end_time": "2024-08-05T20:06:01.858111500Z", + "start_time": "2024-08-05T20:06:01.830915300Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[Project]\n", + "\n", + "# project name\n", + "ProjectName = pm_abcd_mrtm_watch_1971_2001\n", + "\n", + "# full path to directory containing input and output directories\n", + "RootDir = C:\\xanthos-dev\\xanthos-dev\\data\\example\n", + "\n", + "# input directory name contained in root\n", + "InputFolder = input\n", + "\n", + "# output directory name containined in root\n", + "OutputFolder = output\n", + "\n", + "# directory name where the reference data is contained in the input directory\n", + "RefDir = reference\n", + "\n", + "# directory name where PET dir is\n", + "pet_dir = pet\n", + "\n", + "# directory name where the routing data is contained in the input directory\n", + "RoutingDir = routing\n", + "\n", + "# directory name where the runoff data is contained in the input directory\n", + "RunoffDir = runoff\n", + "\n", + "# directory name where the diagnostics directory is contained in the input directory\n", + "DiagDir = diagnostics\n", + "\n", + "# directory name where the accessible water input file directory is contained\n", + "AccWatDir = accessible_water\n", + "\n", + "# directory name where the hydropower potential input file directory is contained\n", + "HydActDir = hydropower_actual\n", + "\n", + "# HistFlag = True, historic mode ; = False, future mode\n", + "HistFlag = True\n", + "\n", + "# number of basins to process\n", + "n_basins = 235\n", + "\n", + "# start and end year of the run\n", + "StartYear = 1971\n", + "EndYear = 2001\n", + "\n", + "# which variables to output, any of:\n", + "# - 'pet' (potential evapotranspiration)\n", + "# - 'aet' (actual evapotranspiration)\n", + "# - 'q' (runoff)\n", + "# - 'soilmoisture' (soil moisture)\n", + "# - 'avgchflow' (average channel flow)\n", + "output_vars = pet, aet, q, soilmoisture, avgchflow\n", + "\n", + "# output format; one of 0 (netcdf file), 1 (csv file), 2 (matlab file), 3 (parquet file)\n", + "OutputFormat = 1\n", + "\n", + "# Default output unit is 0 = mm/month, 1 = km3/month\n", + "OutputUnit = 1\n", + "\n", + "# Default is 0, if OutputInYear = 1, then the output will combine 12-month results into annual result\n", + "# (unit will be mm/year or km3/year)\n", + "OutputInYear = 1\n", + "\n", + "# aggregate runoff by basin/country/region; Default is 0 for False, 1 for True\n", + "AggregateRunoffBasin = 1\n", + "AggregateRunoffCountry = 1\n", + "AggregateRunoffGCAMRegion = 1\n", + "\n", + "# perform diagnostics defined in [Diagnostics]; Default is 0 for False, 1 for True\n", + "PerformDiagnostics = 1\n", + "\n", + "# create time series plots defined in [TimeSeriesPlot]; Default is 0 for False, 1 for True\n", + "CreateTimeSeriesPlot = 0\n", + "\n", + "# calculate drought statistics; Default is 0 for False, 1 for True\n", + "CalculateDroughtStats = 1\n", + "\n", + "# calculate accessible water; Default is 0 for False, 1 for True\n", + "CalculateAccessibleWater = 1\n", + "\n", + "# calculate hydropower potential; Default is 0; if = 1\n", + "CalculateHydropowerPotential = 1\n", + "\n", + "# calculate hydropower actual; Default is 0 for False, 1 for True\n", + "CalculateHydropowerActual = 1\n", + "\n", + "# run calibration mode; Default is 0 for False, 1 for True\n", + "Calibrate = 0\n", + "\n", + "\n", + "# set PET module type and individual parameters\n", + "[PET]\n", + "# name of the PET module you wish to use (e.g., penman-monteith)\n", + "pet_module = pm\n", + "\n", + "[[penman-monteith]]\n", + "# directory name of the pet model\n", + "pet_dir = penman_monteith\n", + "\n", + "# monthly mean surface air temperature degrees C\n", + "pm_tas = tas_watch_monthly_degc_1971_2001.npy\n", + "\n", + "# monthly mean minimum temperature degrees C\n", + "pm_tmin = tasmin_watch_monthly_degc_1971_2001.npy\n", + "\n", + "# relative humidity in percent\n", + "pm_rhs = rhs_watch_monthly_percent_1971_2001.npy\n", + "\n", + "# rlds\n", + "pm_rlds = rlds_watch_monthly_wperm2_1971_2001.npy\n", + "\n", + "# rsds\n", + "pm_rsds = rsds_watch_monthly_wperm2_1971_2001.npy\n", + "\n", + "# wind\n", + "pm_wind = wind_watch_monthly_mpers_1971_2001.npy\n", + "\n", + "# land cover data\n", + "pm_lct = lucc1901_2010_lump.npy\n", + "\n", + "# the number of land cover classes in the input data\n", + "pm_nlcs = 8\n", + "\n", + "# the land class index, starting at 0, of water in the land cover data\n", + "pm_water_idx = 0\n", + "\n", + "# the land class index, starting at 0, of snow in the land cover data\n", + "pm_snow_idx = 6\n", + "\n", + "# a comma-separated string of years in the input land cover data\n", + "pm_lc_years = 1900, 1910, 1920, 1930, 1940, 1950, 1960, 1970, 1980, 1990, 2000, 2005, 2010\n", + "\n", + "\n", + "# Set runoff module type and individual parameters\n", + "[Runoff]\n", + "# name of the runoff module you wish to use (gwam or abcd)\n", + "runoff_module = abcd\n", + "\n", + "# parameters is using the ABCD model\n", + "[[abcd]]\n", + "# source directory name for the ABCD runoff module\n", + "runoff_dir = abcd\n", + "\n", + "# calibration parameters file with path for ABCDM per basin\n", + "calib_file = pars_watch_1971_1990_decadal_lc.npy\n", + "\n", + "# the number of months from the start of the data that you wish to use for spin up\n", + "runoff_spinup = 372\n", + "\n", + "# the number of jobs to use when running basins parallel (-2, all but one core; -1, all cores; 8, 8 cores)\n", + "jobs = -1\n", + "\n", + "# minimum temperature file that is stored in the model directory in deg C\n", + "TempMinFile = C:\\xanthos-dev\\xanthos-dev\\data\\example\\input/climate/pr_gpcc_watch_monthly_mmpermth_1971_2001.npy\n", + "\n", + "# monthly average precipitation in mm/mth\n", + "PrecipitationFile = C:\\xanthos-dev\\xanthos-dev\\data\\example\\input/climate/pr_gpcc_watch_monthly_mmpermth_1971_2001.npy\n", + "\n", + "\n", + "# Set routing module type and individual parameters\n", + "[Routing]\n", + "# name of the routing module you wish to use (mrtm)\n", + "routing_module = mrtm\n", + "\n", + "[[mrtm]]\n", + "# directory name of the routing model\n", + "routing_dir = mrtm\n", + "\n", + "# spin-up in months for the router\n", + "routing_spinup = 372\n", + "\n", + "# channel velocity\n", + "channel_velocity = velocity_half_degree.npy\n", + "\n", + "# flow distance\n", + "flow_distance = DRT_half_FDISTANCE_globe.txt\n", + "\n", + "# flow direction\n", + "flow_direction = DRT_half_FDR_globe_bystr50.txt\n", + "\n", + "\n", + "[Diagnostics]\n", + "# Comparison with other models:\n", + "# Estimates of average total annual runoff (km^3/yr)\n", + "# The comparison data file needs to be preprocessed.\n", + "# Unit: km3/year\n", + "# Runoff\n", + "# - VIC The major comparison, Dimension: (67420, 30)\n", + "# - WBM Ref comparison: WBM (Fekete et al., 2000) and WBMc (Fekete et al., 2000)\n", + "# are also used as additional comparisons (2 column csv files), Dimension: (67420, 1)\n", + "# - UNH Ref comparison: averaged UNH-GRDC 1986-1995, Dimension: (67420, 1)\n", + "VICDataFile = vic_watch_hist_nosoc_co2_qtot_global_annual_1971_2000.nc\n", + "WBMDataFile = wbm_qestimates.csv\n", + "WBMCDataFile = wbmc_qestimates.csv\n", + "UNHDataFile = UNH_GRDC_average_annual_1986_1995.nc\n", + "\n", + "# Define the Scale to use for Runoff Diagnostics : 0 = All (default), 1 = Basin, 2 = Country, 3 = Region\n", + "Scale = 0\n", + "\n", + "\n", + "[Drought]\n", + "# The drought statistics post-processing module. It can be used to either\n", + "# calculate quantile-based drought thresholds, or to compute Severity,\n", + "# Intensity, and Duration statistics.\n", + "#\n", + "# If the parameter drought_thresholds is provided, drought statistics will be\n", + "# outputted, otherwise thresholds will be calculated.\n", + "\n", + "# Which output variable to use, either 'q' (runoff) or 'soilmoisture' (soil moisture)\n", + "drought_var = q\n", + "\n", + "# Inclusive year range over which to calculate drought thresholds\n", + "threshold_start_year = 1971\n", + "threshold_end_year = 2001\n", + "\n", + "# Number of periods to calculate thresholds for. Generally either 1 (single\n", + "# threshold for all periods), or 12 (thresholds by month)\n", + "threshold_nper = 12\n", + "\n", + "\n", + "[AccessibleWater]\n", + "# Reference data for accessible water module\n", + "# Reservoir capacity at basin level\n", + "# Baseflow index (BFI) file\n", + "ResCapacityFile = total_reservoir_storage_capacity_BM3.csv\n", + "BfiFile = bfi_per_basin.csv\n", + "\n", + "# HistEndYear: End year of historical data, e.g. 2005\n", + "HistEndYear = 2001\n", + "GCAM_StartYear = 1971\n", + "GCAM_EndYear = 2001\n", + "GCAM_YearStep = 1\n", + "\n", + "# A parameter for moving average\n", + "MovingMeanWindow = 9\n", + "\n", + "# Used to calculate Environmental Flow Requirements (EFR) per basin, for example, use 10% of historical mean\n", + "Env_FlowPercent = 0.1\n", + "\n", + "\n", + "[HydropowerPotential]\n", + "# Inputs to hydropower potential module\n", + "\n", + "# Start date in M/YYYY format\n", + "hpot_start_date = \"1/1971\"\n", + "\n", + "# Quantile of monthly flow above which additional power is unavailable; values from 0.0 to 1.0\n", + "q_ex = 0.7\n", + "\n", + "# Plant efficiency; values from 0.0 to 1.0\n", + "ef = 0.8\n", + "\n", + "\n", + "[HydropowerActual]\n", + "# Input to hydropower dam simulation module\n", + "\n", + "# Start date in M/YYYY format\n", + "hact_start_date = \"1/1971\"\n", + "\n", + "\n", + "[TimeSeriesPlot]\n", + "Scale = 1\n", + "MapID = 999\n" + ] + } + ], + "source": [ + "# path to the example folder\n", + "example_dir = os.path.join(data_dir, 'example')\n", + "\n", + "# path to the configuration (.ini) file\n", + "config_file = os.path.join(example_dir, 'pm_abcd_mrtm.ini')\n", + "\n", + "# take a look at configuration file\n", + "f = open(config_file, 'r')\n", + "print(f.read())\n", + " \n", + "f.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Modify the configuration file by changing `RootDir`, `TempMinFile`, `PrecipitationFile` to represent your local path. There are two options to change your configuration file:\n", + "\n", + "* Option 1: change them manually in the `pm_abcd_mrtm.ini`. \n", + "* Option 2: change them using `replace_line` function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# function to replace lines in the text file\n", + "def replace_line(filename, line_number, text):\n", + " \"\"\"\n", + " replace lines in a file.\n", + " \n", + " :filename: string for path to the file\n", + " :line_number: integer for the line number to replace\n", + " :text: string for replacement text\n", + " \"\"\"\n", + " \n", + " with open(filename) as file:\n", + " lines = file.readlines()\n", + " lines[line_number - 1] = text\n", + "\n", + " with open(filename, 'w') as file:\n", + " for line in lines:\n", + " file.write(line)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This will update file paths within the configuraton file\n", + "# Update RootDir\n", + "replace_line(\n", + " filename = config_file,\n", + " line_number = 7,\n", + " text = f'RootDir = {example_dir}\\n'\n", + ")\n", + "\n", + "# Update path to TempMinFile\n", + "TempMinFile_new = os.path.join(example_dir, 'input/climate/pr_gpcc_watch_monthly_mmpermth_1971_2001.npy')\n", + "replace_line(\n", + " filename = config_file,\n", + " line_number = 154,\n", + " text = f'TempMinFile = {TempMinFile_new}\\n'\n", + ")\n", + "\n", + "# Update path to PrecipitationFile\n", + "PrecipitationFile_new = os.path.join(example_dir, 'input/climate/pr_gpcc_watch_monthly_mmpermth_1971_2001.npy')\n", + "replace_line(\n", + " filename = config_file,\n", + " line_number = 157,\n", + " text = f'PrecipitationFile = {PrecipitationFile_new}\\n'\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# take a look at the updated configuration file\n", + "f = open(config_file, 'r')\n", + "print(f.read())\n", + " \n", + "f.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Run Xanthos" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "To run xanthos, pass the path of the configuration file to `xanthos.run_model`." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2024-08-05T20:23:28.595265700Z", + "start_time": "2024-08-05T20:06:01.841022800Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO: ProjectName : pm_abcd_mrtm_watch_1971_2001\n", + "INFO: InputFolder : C:\\xanthos-dev\\xanthos-dev\\data\\example\\input\n", + "INFO: OutputFolder: C:\\xanthos-dev\\xanthos-dev\\data\\example\\output\\pm_abcd_mrtm_watch_1971_2001\n", + "INFO: StartYear - End Year: 1971-2001\n", + "INFO: Number of Months : 372\n", + "INFO: Running: Historic Mode\n", + "INFO: Diagnostics will be performed using the data file: C:\\xanthos-dev\\xanthos-dev\\data\\example\\input\\diagnostics\\vic_watch_hist_nosoc_co2_qtot_global_annual_1971_2000.nc\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\knig694\\AppData\\Local\\miniconda3\\envs\\xanthos\\Lib\\site-packages\\xanthos\\data_reader\\data_load.py:359: UserWarning: Reading `.npy` or `.npz` file required additional header parsing as it was created on Python 2. Save the file again to speed up loading and avoid this warning.\n", + " data = np.load(fn)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO: ---Simulation in progress...\n", + "INFO: \tProcessing PET...\n", + "INFO: \t\tProcessing Years: 1971 to 1972\n", + "INFO: \t\tProcessing Years: 1972 to 1973\n", + "INFO: \t\tProcessing Years: 1973 to 1974\n", + "INFO: \t\tProcessing Years: 1974 to 1975\n", + "INFO: \t\tProcessing Years: 1975 to 1976\n", + "INFO: \t\tProcessing Years: 1976 to 1977\n", + "INFO: \t\tProcessing Years: 1977 to 1978\n", + "INFO: \t\tProcessing Years: 1978 to 1979\n", + "INFO: \t\tProcessing Years: 1979 to 1980\n", + "INFO: \t\tProcessing Years: 1980 to 1981\n", + "INFO: \t\tProcessing Years: 1981 to 1982\n", + "INFO: \t\tProcessing Years: 1982 to 1983\n", + "INFO: \t\tProcessing Years: 1983 to 1984\n", + "INFO: \t\tProcessing Years: 1984 to 1985\n", + "INFO: \t\tProcessing Years: 1985 to 1986\n", + "INFO: \t\tProcessing Years: 1986 to 1987\n", + "INFO: \t\tProcessing Years: 1987 to 1988\n", + "INFO: \t\tProcessing Years: 1988 to 1989\n", + "INFO: \t\tProcessing Years: 1989 to 1990\n", + "INFO: \t\tProcessing Years: 1990 to 1991\n", + "INFO: \t\tProcessing Years: 1991 to 1992\n", + "INFO: \t\tProcessing Years: 1992 to 1993\n", + "INFO: \t\tProcessing Years: 1993 to 1994\n", + "INFO: \t\tProcessing Years: 1994 to 1995\n", + "INFO: \t\tProcessing Years: 1995 to 1996\n", + "INFO: \t\tProcessing Years: 1996 to 1997\n", + "INFO: \t\tProcessing Years: 1997 to 1998\n", + "INFO: \t\tProcessing Years: 1998 to 1999\n", + "INFO: \t\tProcessing Years: 1999 to 2000\n", + "INFO: \t\tProcessing Years: 2000 to 2001\n", + "INFO: \t\tProcessing Years: 2001 to 2001\n", + "INFO: \tPET processed in 284.3404722213745 seconds---\n", + "INFO: \tProcessing Runoff...\n", + "INFO: \t\tProcessing spin-up and simulation for basins 1...235\n", + "INFO: \tRunoff processed in 7.384638071060181 seconds---\n", + "INFO: \tProcessing Routing...\n", + "INFO: \tRouting processed in 663.9755194187164 seconds---\n", + "INFO: ---Simulation has finished successfully: 955.7092554569244 seconds ---\n", + "INFO: ---Start Accessible Water:\n", + "INFO: ---Accessible Water has finished successfully: 5.380142688751221 seconds ------\n", + "INFO: ---Start Drought Statistics:\n", + "INFO: \tCalculating drought thresholds\n", + "INFO: ---Drought Statistics has finished successfully: 0.8193960189819336 seconds ------\n", + "INFO: ---Start Hydropower Potential:\n", + "INFO: ---Hydropower Potential has finished successfully: 8.983213663101196 seconds ------\n", + "INFO: ---Start Hydropower Actual:\n", + " [[ 0. 0. 0. ... 0. 0.\n", + " 0. ]\n", + " [ 0. 0. 0. ... 0. 0.\n", + " 0. ]\n", + " [ 5.51874663 7.79450363 8.70009545 ... 8.76897534 9.35317893\n", + " 10.28142478]\n", + " ...\n", + " [ 0. 0. 0. ... 0. 0.\n", + " 0. ]\n", + " [ 0. 0. 0. ... 0. 0.\n", + " 0. ]\n", + " [ 0. 0. 0. ... 0. 0.\n", + " 0. ]]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\knig694\\AppData\\Local\\miniconda3\\envs\\xanthos\\Lib\\site-packages\\xanthos\\hydropower\\actual.py:48: UserWarning: Reading `.npy` or `.npz` file required additional header parsing as it was created on Python 2. Save the file again to speed up loading and avoid this warning.\n", + " self.rule_curves = np.load(settings.rule_curves) # rule curves for all 1593 dams\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO: ---Hydropower Actual has finished successfully: 52.48439311981201 seconds ------\n", + "INFO: ---Start Diagnostics:\n", + "INFO: ---Diagnostics has finished successfully: 0.24135708808898926 seconds ------\n", + "INFO: ---Output simulation results:\n", + "DEBUG: Outputting data annually\n", + "DEBUG: Unit is km3peryear\n", + "DEBUG: pet output dimension is (67420, 31)\n", + "DEBUG: aet output dimension is (67420, 31)\n", + "DEBUG: q output dimension is (67420, 31)\n", + "DEBUG: soilmoisture output dimension is (67420, 31)\n", + "DEBUG: avgchflow output dimension is (67420, 31)\n", + "INFO: Aggregating by Basin\n", + "INFO: Aggregating by Country\n", + "INFO: Aggregating by GCAM Region\n", + "INFO: Aggregated unit is km3peryear\n", + "INFO: ---Output finished: 17.97227382659912 seconds ---\n", + "INFO: End of pm_abcd_mrtm_watch_1971_2001\n" + ] + } + ], + "source": [ + "import xanthos\n", + "\n", + "# run Xanthos \n", + "xanthos.run_model(config_file)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Use Xanthos Module" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "User can use any `Xantho` module individually by providing required input. The following example shows how to calculate accessible water using the `AccessibleWater` module. `AccessibleWater` module requires three inputs: \n", + "1. Configuration object: use xanthos module `ConfigReader` to load\n", + "2. Loaded data object: use xanthos module `DataLoader` to load\n", + "3. Monthly runoff in each grid cell\n", + " * Format requirement: 2D array ordered by Xanthos id for [grid_cell, month].\n", + " * Grid cell resolution: Xanthos grid cell is at 0.5 degree xanthos grid resolution and the id is from 1 to 67420. Please find latitude and longitude for Xanthos grid cells in `example/input/referece/coordinate.csv`.\n", + " * Unit requirement: the runoff values should be in *mm/month*.\n", + " * Note: please make sure the monthly runoff has the same time period specified in the configuration file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "# since we do not have monthly runoff, we make a ramdom example of runoff time seris\n", + "# the runoff data will be 67420 grid cells by 372 months (match 1971 - 2001 in the configuration)\n", + "runoff = np.random.random((67420, 372))\n", + "print(runoff)\n", + "\n", + "# Create a demo folder \n", + "demo_dir = os.path.join(data_dir, 'example', 'output', 'demo')\n", + "if not os.path.exists(demo_dir):\n", + " os.makedirs(demo_dir, exist_ok=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "from xanthos import ConfigReader\n", + "from xanthos.data_reader.data_load import DataLoader\n", + "from xanthos.accessible.accessible import AccessibleWater\n", + "\n", + "# load configuration setting using ConfigReader\n", + "config = ConfigReader(ini=config_file)\n", + "\n", + "# Update the output folder path to demo folder to avoid overwriting the exisitng file\n", + "config.OutputFolder = demo_dir\n", + "config.update({})\n", + "\n", + "# load reference data\n", + "data = DataLoader(config_obj=config)\n", + "\n", + "# calculate accessible water (~ 15 seconds)\n", + "AccessibleWater(settings=config, ref=data, runoff=runoff)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "***" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Input and Output Data" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "In this section, we will\n", + "* Learn the data format for Xanthos inputs and outputs\n", + "* Visualize Xanthos inputs and outputs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Plotting Functions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import xanthos\n", + "\n", + "import os\n", + "from scipy import stats\n", + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.colors as colors\n", + "import matplotlib.cbook as cbook\n", + "from matplotlib import cm\n", + "\n", + "def name_columns(arr, start_yr=1971):\n", + " \"\"\"\n", + " find cooresponding year month names for the array.\n", + "\n", + " :param arr: array with format [grid by year-month]\n", + " :param start_yr: integer of data start year\n", + "\n", + " :return: string vector and dictionary\n", + " \"\"\"\n", + "\n", + " cols_str = []\n", + " cols_dict = {}\n", + " for i in range(0, arr.shape[1], 1):\n", + " mod = i%12\n", + " str_yr = str(start_yr)\n", + "\n", + " if mod == 0:\n", + " cols_str.append(str_yr)\n", + "\n", + " if str_yr in cols_dict:\n", + " cols_dict[str_yr].append(i)\n", + " else:\n", + " cols_dict[str_yr] = [i]\n", + "\n", + " elif mod == 11:\n", + " cols_str.append(str_yr)\n", + "\n", + " if str_yr in cols_dict:\n", + " cols_dict[str_yr].append(i)\n", + " else:\n", + " cols_dict[str_yr] = [i]\n", + "\n", + " start_yr += 1\n", + " else:\n", + " cols_str.append(str_yr)\n", + "\n", + " if str_yr in cols_dict:\n", + " cols_dict[str_yr].append(i)\n", + " else:\n", + " cols_dict[str_yr] = [i]\n", + "\n", + " return cols_str, cols_dict\n", + "\n", + "def arr_to_df(arr, stat='mean', start_yr=1971, from_yr=False, through_yr=False):\n", + " \"\"\"\n", + " Calculate certain stats on xanthos input array (usually climate data) and convert to certain data frame format.\n", + "\n", + " :param arr: array for xanthos input or similar format [grid by year-month]\n", + " :param stat: string for stats to apply ['min', 'max', 'mean', 'median']\n", + " :param start_yr: integer for data start year\n", + " :param from_yr: integer for start year to filter\n", + " :param through_yr: integer for through year to filter\n", + "\n", + " :return: data frame\n", + " \"\"\"\n", + "\n", + " cols_str, cols_dict = name_columns(arr, start_yr=start_yr)\n", + "\n", + " df = pd.DataFrame(data=arr, columns=cols_str)\n", + "\n", + " # select target years to process\n", + " if from_yr:\n", + " idx_start = min(cols_dict[str(from_yr)])\n", + " else:\n", + " idx_start = 0\n", + "\n", + " if through_yr:\n", + " idx_end = max(cols_dict[str(through_yr)])\n", + " else:\n", + " idx_end = df.shape[1]\n", + "\n", + " df = df.iloc[:, idx_start:idx_end]\n", + "\n", + " df['key'] = 'value'\n", + "\n", + " if stat == 'mean':\n", + " dfx = df.groupby('key').mean().T\n", + " elif stat == 'max':\n", + " dfx = df.groupby('key').max().T\n", + " elif stat == 'min':\n", + " dfx = df.groupby('key').min().T\n", + " elif stat == 'median':\n", + " dfx = df.groupby('key').median().T\n", + " else:\n", + " raise ValueError(\"Please enter stat of 'mean', 'median', 'min', 'max'.\")\n", + "\n", + " return dfx\n", + "\n", + "def format_data(sim, obs, id=229, from_yr=1971, through_yr=2010):\n", + " \"\"\"\n", + " Combine sim and obs and format to [basin_id, basin_name, year, time, obs, sim].\n", + "\n", + " :param sim: data frame of xanthos output at basin scale\n", + " :param obs: data frame of observation [basin, year, month, q]\n", + " :param id: integer for selected basin id, or 'global' to aggregate all basins together\n", + " :param from_yr: integer for start year to filter data\n", + " :param through_yr: integer for end year to filter data\n", + "\n", + " :return: data frame\n", + " \"\"\"\n", + "\n", + " # melt all month_year columns to time and value for simulated output\n", + " sim_melt = sim.melt(id_vars=['id', 'name'])\n", + "\n", + " # format simulated output\n", + " sim_melt = sim_melt.rename(columns={'id': 'basin', 'variable': 'year'})\n", + " sim_melt['year'] = sim_melt.year.astype(int)\n", + "\n", + " # aggregate observation to annual\n", + " obs_annual = obs.groupby(['basin', 'year'], as_index=False).sum().drop(['month'], axis=1)\n", + "\n", + " # merge observation and simulation\n", + " df = pd.merge(sim_melt, obs_annual, how='left', on=('basin', 'year'))\n", + " df = df.rename(columns={'value': 'sim', 'q': 'obs', 'basin':'basin_id', 'name': 'basin_name'})\n", + "\n", + " # select basin and year range to plot\n", + " if id == 'global':\n", + " df_format = df[(df.year>=from_yr) & (df.year<=through_yr)].reset_index(drop=True)\n", + " df_format = df_format.groupby(['year'], as_index=False).sum()\n", + " df_format['basin_id'] = 'All Basins'\n", + " df_format['basin_name'] = id\n", + " else:\n", + " df_format = df[df.basin_id.isin(id) & (df.year>=from_yr) & (df.year<=through_yr)].reset_index(drop=True)\n", + "\n", + " # add time\n", + " df_format['time'] = pd.to_datetime(df_format.year, format='%Y')\n", + "\n", + " return df_format\n", + "\n", + "def plot_single_line(dfx, title='', x_label='', y_label=''):\n", + " \"\"\"\n", + " Plot a single time series.\n", + "\n", + " :param dfx: data frame with a column of values\n", + " :param title: string for figure title\n", + " :param x_label: string for x axis label\n", + " :param y_label: string for y axis label\n", + " \"\"\"\n", + "\n", + " # plt.figure()\n", + " with plt.style.context(\"seaborn-white\"):\n", + " fig, ax = plt.subplots(figsize=(16, 8), constrained_layout=False)\n", + " dfx.plot(kind='line', legend=False, title=title, colormap=\"cubehelix\", ax=ax)\n", + " ax.set_title(title)\n", + " ax.set_xlabel(x_label)\n", + " ax.set_ylabel(y_label)\n", + " ax.set_facecolor('white')\n", + " plt.show()\n", + "\n", + "def plot_comparison(df_plot, y_label=''):\n", + " \"\"\"\n", + " Plot comparison between observations and simulations.\n", + "\n", + " :param df_plot: data frame with time, obs and sim\n", + " :param y_label: string for y axis label\n", + " \"\"\"\n", + "\n", + " # title\n", + " title = str(df_plot['basin_id'].unique()[0]) + ' - ' + df_plot['basin_name'].unique()[0]\n", + "\n", + " # Plot\n", + " with plt.style.context(\"seaborn-white\"):\n", + " fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=False)\n", + " df_plot.plot(x = 'time', y=['obs', 'sim'], kind='line', color=['black', 'dodgerblue'],\n", + " lw=3, legend=True, ax=ax)\n", + " ax.set_title(title, fontsize=18, fontweight='bold')\n", + " ax.set_xlabel('Time', fontsize=18)\n", + " ax.set_ylabel(y_label, fontsize=18)\n", + " plt.xticks(fontsize=16)\n", + " plt.yticks(fontsize=16)\n", + " ax.legend(fontsize=16)\n", + " ax.grid()\n", + " plt.show()\n", + " \n", + "def plot_diagnostics(data, titlestr):\n", + " \"\"\"\n", + " Plot diagnostics.\n", + " \n", + " :param data: array from diagnostic output\n", + " :param titlestr: string for output scale ('Basin', 'Country', 'Region')\n", + " \"\"\"\n", + " \n", + " fig = plt.figure(figsize=(10,6), constrained_layout=False)\n", + " ax = plt.gca()\n", + " ax.loglog([0.01, 100000], [0.01, 100000], 'grey')\n", + " ax.scatter(data[:, 0], data[:, 1], c='aquamarine', alpha=0.7, edgecolors='black', label='VIC_1971-2000')\n", + " ax.scatter(data[:, 0], data[:, 2], c='salmon', alpha=0.7, edgecolors='black', label='WBM')\n", + " ax.scatter(data[:, 0], data[:, 3], c='Blue', alpha=0.7, edgecolors='black', label='WBMc')\n", + " ax.scatter(data[:, 0], data[:, 4], c='white', alpha=0.7, edgecolors='black', label='UNH/GRDC_1986-1995')\n", + " ax.set_yscale('log')\n", + " ax.set_xscale('log')\n", + " ax.axis([0.01, 1e5, 0.01, 1e5])\n", + " ax.legend(loc='lower right', bbox_to_anchor=(1, 0), fontsize=12)\n", + " plt.title('Hydro Model Diagnostics at ' + titlestr + ' Scale', fontsize=14, fontweight='bold')\n", + " plt.xlabel(r'Simulated Averaged Annual Runoff ($km^3$/yr)', fontsize=14)\n", + " plt.ylabel(r'Averaged Annual Runoff ($km^3$/yr)', fontsize=14)\n", + "\n", + "def plot_map(arr, coord, legend_label=None, cmap=None):\n", + " \"\"\"\n", + " Plot spatial map.\n", + " \n", + " :param arr: array of grid cells by year-month\n", + " :param coord: data frame for coordinates [lat, lon]\n", + " :param legend_label: string for legend label\n", + " :param cmap: string for color palette\n", + " \n", + " \"\"\"\n", + "\n", + " cols_str, cols_dict = name_columns(tas, start_yr=1971)\n", + "\n", + " df = pd.DataFrame(data=arr, columns=cols_str).mean(axis=1).rename('value')\n", + "\n", + " df = pd.concat([df, coord], axis=1)\n", + "\n", + " fig = plt.figure(figsize=(15,6), constrained_layout=True)\n", + " spec = fig.add_gridspec(1, 1)\n", + " ax = fig.add_subplot(spec[0, 0])\n", + " p = ax.scatter(df.lon, df.lat, s=3, c=df.value, cmap=cmap)\n", + " legend_kwds = {'label':legend_label,\n", + " 'shrink':1}\n", + "\n", + " cbar = plt.colorbar(p, **legend_kwds)\n", + " cbar.ax.set_ylabel(legend_label, rotation=270)\n", + " plt.xlabel(\"Longitude\")\n", + " plt.ylabel(\"Latitude\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Read Input and Output Data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# read runoff observation from input folder\n", + "obs_dir = os.path.join(data_dir, 'example', 'input', 'calibration')\n", + "obs_file = 'vic_watch_basin_km3_1971_2001_monthly.csv'\n", + "runoff_obs = pd.read_csv(os.path.join(obs_dir, obs_file))\n", + "\n", + "# xanthos coordinates\n", + "coord = pd.DataFrame(data.coords[:, 1:3], columns=['lon', 'lat'])\n", + "\n", + "# we can get temperature input from loaded data\n", + "# Load all input data using xanthos module `DataLoader`\n", + "tas = data.tair_load\n", + "\n", + "# read example outputs\n", + "output_dir = os.path.join(data_dir, 'example', 'output', 'pm_abcd_mrtm_watch_1971_2001')\n", + "\n", + "# runoff aggregated to basin scale\n", + "runoff_basin_file = 'Basin_runoff_km3peryear_pm_abcd_mrtm_watch_1971_2001.csv'\n", + "\n", + "# runoff at 0.5 degree\n", + "runoff_grid_file = 'q_km3peryear_pm_abcd_mrtm_watch_1971_2001.csv'\n", + "\n", + "# read runoff as data frame\n", + "runoff_basin = pd.read_csv(os.path.join(output_dir, runoff_basin_file))\n", + "runoff_grid = pd.read_csv(os.path.join(output_dir, runoff_grid_file))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Xanthos Input Examples" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "Global climate data usually are stored in netCDF files. `xanthos` requires climate inputs as numpy files (e.g., `.np`). If users want to provide different climate inputs from the example data, please convert the climate data to required format as [grid by year-month]. Standard Xanthos resolution is 0.5 degree, and there are 67420 inland grid cells in total by year-month." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# input climate data format requirement 2D array [67420 grid cells, year-month, ...]\n", + "print(tas.shape)\n", + "tas[1:5,]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# input climate data time series\n", + "dfx = arr_to_df(arr=tas, stat='mean')\n", + "plot_single_line(dfx=dfx,\n", + " title='Global Mean Temperature',\n", + " y_label='Degree C')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# spatial mean temperature across 1971 - 2001\n", + "plot_map(arr=tas,\n", + " coord=coord,\n", + " legend_label='Temperature (degree C)',\n", + " cmap='RdBu')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# global observed runoff format requirement [basin, year, month, q]\n", + "runoff_obs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Xanthos Output Structure" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "Xanthos outputs are at 0.5 degree resolution in CSV files. Some outputs (e.g., runoff) are also aggregated to GCAM region, basin, and country scale." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# runoff at xanthos grid cells (67420 cells)\n", + "print('The output is in the unit of', config.OutputUnitStr)\n", + "runoff_grid" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# runoff at basin scale (235 basins)\n", + "print('The output is in the unit of', config.OutputUnitStr)\n", + "runoff_basin" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Output Visualization" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# Compare time series of simulation and observation for an individual basin\n", + "df_plot = format_data(sim=runoff_basin,\n", + " obs=runoff_obs,\n", + " id=[217],\n", + " from_yr=1972,\n", + " through_yr=2001)\n", + "plot_comparison(df_plot=df_plot,\n", + " y_label='Annual Runoff ($km^3$/year)')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# Compare time series of simulation and observation for all basins together\n", + "df_plot = format_data(sim=runoff_basin,\n", + " obs=runoff_obs,\n", + " id='global',\n", + " from_yr=1972,\n", + " through_yr=2001)\n", + "plot_comparison(df_plot=df_plot,\n", + " y_label='Annual Runoff ($km^3$/year)')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# Diagnostics with other global data\n", + "runoff_diag = pd.read_csv(os.path.join(data_dir, \n", + " 'example', 'output', 'pm_abcd_mrtm_watch_1971_2001', \n", + " 'Diagnostics_Runoff_Basin_Scale_km3peryr.csv')).to_numpy()\n", + "\n", + "# plot diagnostics\n", + "plot_diagnostics(data=runoff_diag[1:, 1:],\n", + " titlestr='Basin')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# spatial mean runoff across 1971 - 2001\n", + "plot_map(arr=runoff_grid,\n", + " coord=coord,\n", + " legend_label='Runoff (km3/year)',\n", + " cmap='viridis')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/pyproject.toml b/pyproject.toml index d600d32..d364ca2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,17 +28,6 @@ dependencies = [ [project.optional-dependencies] test = [] -[project.dependencies] -numpy = ">=1.24.4" -scipy = ">=1.6" -pandas = "~=2.0.3" -configobj = ">=5.0.8" -joblib = ">=1.3.2" -matplotlib = ">=3.7.2" -xarray = ">=2023.8.0" -toml = ">=0.10.2" -requests = "*" - [project.urls] Repository = "https://github.com/JGCRI/xanthos" Documentation = "https://github.com/JGCRI/xanthos/wiki" diff --git a/xanthos/hydropower/actual.py b/xanthos/hydropower/actual.py index 6206123..97bb733 100644 --- a/xanthos/hydropower/actual.py +++ b/xanthos/hydropower/actual.py @@ -22,9 +22,9 @@ class HydropowerActual: Compute country and GCAM-region level hydropower production time series based on xanthos streamflow output. Gridded streamflow is used to drive dam simulations for 1593 large dams (~54% global hydropower installed capacity). - Each dam is has been pre-assigned an optimized look-up table, which assigns a turbine release at each time step + Each dam has been pre-assigned an optimized look-up table, which assigns a turbine release at each time step using current reservoir storage, inflow and month of year. Power output time series are summed across dams for each - country and scaled up to account for unsimulated capacity (i.e., for dams not represented in the model). + country and scaled up to account for non-simulated capacity (i.e., for dams not represented in the model). """ secs_in_month = 2629800 # number of seconds in an average month @@ -34,6 +34,8 @@ class HydropowerActual: mwh_to_exajoule = 3.6 * (10 ** -9) # megawatts to exajoules def __init__(self, settings, q_grids): + print(settings, q_grids) + """Load inputs, run simulation, and output results.""" self.settings = settings self.q_grids = q_grids @@ -80,13 +82,12 @@ def __init__(self, settings, q_grids): # run simulation self.hydro_sim() - # convert power production time series to GCAM region enery production + # convert power production time series to GCAM region energy production self.to_region() # write output self.write_output() - @staticmethod def find_nearest(array, value): """Get value from within an array closest to a value.""" @@ -103,6 +104,7 @@ def get_grid_id(self, longlat): lon = self.find_nearest(self.loc_refs["long"], longlat["LONG_DD"]) lat = self.find_nearest(self.loc_refs["lati"], longlat["LAT_DD"]) return int(self.loc_refs[(self.loc_refs["long"] == lon) & (self.loc_refs["lati"] == lat)]["ID"].iloc[0]) + def get_drain_area(self, x, drainage_area): """Get drainage area implied by the routing network.""" lonseq = np.unique(self.loc_refs["long"])